@critical-path/core 0.35.0 → 0.36.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 (187) hide show
  1. package/README.md +11 -0
  2. package/dist/engine/index.d.ts +2 -0
  3. package/dist/engine/index.d.ts.map +1 -1
  4. package/dist/engine/index.js +25 -2
  5. package/dist/engine/index.js.map +1 -1
  6. package/dist/types/index.d.ts +11 -0
  7. package/dist/types/index.d.ts.map +1 -1
  8. package/package.json +5 -1
  9. package/CHANGELOG.md +0 -584
  10. package/dist/deliverables.test.d.ts +0 -2
  11. package/dist/deliverables.test.d.ts.map +0 -1
  12. package/dist/deliverables.test.js +0 -232
  13. package/dist/deliverables.test.js.map +0 -1
  14. package/dist/domain/calendar.test.d.ts +0 -2
  15. package/dist/domain/calendar.test.d.ts.map +0 -1
  16. package/dist/domain/calendar.test.js +0 -181
  17. package/dist/domain/calendar.test.js.map +0 -1
  18. package/dist/domain/cpm.test.d.ts +0 -2
  19. package/dist/domain/cpm.test.d.ts.map +0 -1
  20. package/dist/domain/cpm.test.js +0 -166
  21. package/dist/domain/cpm.test.js.map +0 -1
  22. package/dist/domain/ddd.test.d.ts +0 -2
  23. package/dist/domain/ddd.test.d.ts.map +0 -1
  24. package/dist/domain/ddd.test.js +0 -349
  25. package/dist/domain/ddd.test.js.map +0 -1
  26. package/dist/domain/ladder.test.d.ts +0 -2
  27. package/dist/domain/ladder.test.d.ts.map +0 -1
  28. package/dist/domain/ladder.test.js +0 -213
  29. package/dist/domain/ladder.test.js.map +0 -1
  30. package/dist/domain/metrics.test.d.ts +0 -2
  31. package/dist/domain/metrics.test.d.ts.map +0 -1
  32. package/dist/domain/metrics.test.js +0 -252
  33. package/dist/domain/metrics.test.js.map +0 -1
  34. package/dist/domain/task-duration.test.d.ts +0 -2
  35. package/dist/domain/task-duration.test.d.ts.map +0 -1
  36. package/dist/domain/task-duration.test.js +0 -307
  37. package/dist/domain/task-duration.test.js.map +0 -1
  38. package/dist/domain/workload.test.d.ts +0 -2
  39. package/dist/domain/workload.test.d.ts.map +0 -1
  40. package/dist/domain/workload.test.js +0 -261
  41. package/dist/domain/workload.test.js.map +0 -1
  42. package/dist/engine/actor.test.d.ts +0 -2
  43. package/dist/engine/actor.test.d.ts.map +0 -1
  44. package/dist/engine/actor.test.js +0 -54
  45. package/dist/engine/actor.test.js.map +0 -1
  46. package/dist/engine/authorization.test.d.ts +0 -2
  47. package/dist/engine/authorization.test.d.ts.map +0 -1
  48. package/dist/engine/authorization.test.js +0 -154
  49. package/dist/engine/authorization.test.js.map +0 -1
  50. package/dist/engine/cascade.test.d.ts +0 -2
  51. package/dist/engine/cascade.test.d.ts.map +0 -1
  52. package/dist/engine/cascade.test.js +0 -99
  53. package/dist/engine/cascade.test.js.map +0 -1
  54. package/dist/engine/config.test.d.ts +0 -2
  55. package/dist/engine/config.test.d.ts.map +0 -1
  56. package/dist/engine/config.test.js +0 -46
  57. package/dist/engine/config.test.js.map +0 -1
  58. package/dist/engine/entity-events.test.d.ts +0 -2
  59. package/dist/engine/entity-events.test.d.ts.map +0 -1
  60. package/dist/engine/entity-events.test.js +0 -61
  61. package/dist/engine/entity-events.test.js.map +0 -1
  62. package/dist/index.test.d.ts +0 -2
  63. package/dist/index.test.d.ts.map +0 -1
  64. package/dist/index.test.js +0 -429
  65. package/dist/index.test.js.map +0 -1
  66. package/dist/plugins/plugins.test.d.ts +0 -2
  67. package/dist/plugins/plugins.test.d.ts.map +0 -1
  68. package/dist/plugins/plugins.test.js +0 -137
  69. package/dist/plugins/plugins.test.js.map +0 -1
  70. package/dist/schemas/schemas.test.d.ts +0 -2
  71. package/dist/schemas/schemas.test.d.ts.map +0 -1
  72. package/dist/schemas/schemas.test.js +0 -58
  73. package/dist/schemas/schemas.test.js.map +0 -1
  74. package/dist/status.test.d.ts +0 -2
  75. package/dist/status.test.d.ts.map +0 -1
  76. package/dist/status.test.js +0 -295
  77. package/dist/status.test.js.map +0 -1
  78. package/dist/storage/storage.test.d.ts +0 -2
  79. package/dist/storage/storage.test.d.ts.map +0 -1
  80. package/dist/storage/storage.test.js +0 -236
  81. package/dist/storage/storage.test.js.map +0 -1
  82. package/dist/store/conformance.test.d.ts +0 -2
  83. package/dist/store/conformance.test.d.ts.map +0 -1
  84. package/dist/store/conformance.test.js +0 -15
  85. package/dist/store/conformance.test.js.map +0 -1
  86. package/dist/store/firebase.test.d.ts +0 -2
  87. package/dist/store/firebase.test.d.ts.map +0 -1
  88. package/dist/store/firebase.test.js +0 -103
  89. package/dist/store/firebase.test.js.map +0 -1
  90. package/dist/store/query.test.d.ts +0 -2
  91. package/dist/store/query.test.d.ts.map +0 -1
  92. package/dist/store/query.test.js +0 -89
  93. package/dist/store/query.test.js.map +0 -1
  94. package/dist/store/sqlite.test.d.ts +0 -2
  95. package/dist/store/sqlite.test.d.ts.map +0 -1
  96. package/dist/store/sqlite.test.js +0 -177
  97. package/dist/store/sqlite.test.js.map +0 -1
  98. package/dist/task-state.test.d.ts +0 -2
  99. package/dist/task-state.test.d.ts.map +0 -1
  100. package/dist/task-state.test.js +0 -423
  101. package/dist/task-state.test.js.map +0 -1
  102. package/dist/use-case-validation.test.d.ts +0 -2
  103. package/dist/use-case-validation.test.d.ts.map +0 -1
  104. package/dist/use-case-validation.test.js +0 -281
  105. package/dist/use-case-validation.test.js.map +0 -1
  106. package/dist/utils/fractional-index.test.d.ts +0 -2
  107. package/dist/utils/fractional-index.test.d.ts.map +0 -1
  108. package/dist/utils/fractional-index.test.js +0 -182
  109. package/dist/utils/fractional-index.test.js.map +0 -1
  110. package/dist/utils/key.test.d.ts +0 -2
  111. package/dist/utils/key.test.d.ts.map +0 -1
  112. package/dist/utils/key.test.js +0 -65
  113. package/dist/utils/key.test.js.map +0 -1
  114. package/dist/utils/mentions.test.d.ts +0 -2
  115. package/dist/utils/mentions.test.d.ts.map +0 -1
  116. package/dist/utils/mentions.test.js +0 -114
  117. package/dist/utils/mentions.test.js.map +0 -1
  118. package/dist/webhooks/webhooks.test.d.ts +0 -2
  119. package/dist/webhooks/webhooks.test.d.ts.map +0 -1
  120. package/dist/webhooks/webhooks.test.js +0 -154
  121. package/dist/webhooks/webhooks.test.js.map +0 -1
  122. package/src/deliverables.test.ts +0 -284
  123. package/src/domain/authorization.ts +0 -82
  124. package/src/domain/calendar.test.ts +0 -216
  125. package/src/domain/calendar.ts +0 -502
  126. package/src/domain/cpm.test.ts +0 -189
  127. package/src/domain/cpm.ts +0 -258
  128. package/src/domain/custom-fields.ts +0 -172
  129. package/src/domain/ddd.test.ts +0 -442
  130. package/src/domain/entities.ts +0 -798
  131. package/src/domain/errors.ts +0 -38
  132. package/src/domain/events.ts +0 -369
  133. package/src/domain/graph.ts +0 -70
  134. package/src/domain/index.ts +0 -12
  135. package/src/domain/ladder.test.ts +0 -251
  136. package/src/domain/ladder.ts +0 -474
  137. package/src/domain/metrics.test.ts +0 -288
  138. package/src/domain/metrics.ts +0 -497
  139. package/src/domain/task-duration.test.ts +0 -354
  140. package/src/domain/workload.test.ts +0 -311
  141. package/src/domain/workload.ts +0 -457
  142. package/src/engine/actor.test.ts +0 -63
  143. package/src/engine/authorization.test.ts +0 -199
  144. package/src/engine/cascade.test.ts +0 -121
  145. package/src/engine/config.test.ts +0 -51
  146. package/src/engine/entity-events.test.ts +0 -67
  147. package/src/engine/index.ts +0 -2472
  148. package/src/index.test.ts +0 -514
  149. package/src/index.ts +0 -9
  150. package/src/plugins/index.ts +0 -103
  151. package/src/plugins/plugins.test.ts +0 -161
  152. package/src/schemas/index.ts +0 -402
  153. package/src/schemas/schemas.test.ts +0 -116
  154. package/src/status.test.ts +0 -354
  155. package/src/storage/file-storage.ts +0 -200
  156. package/src/storage/firebase-storage.ts +0 -209
  157. package/src/storage/index.ts +0 -3
  158. package/src/storage/s3.ts +0 -151
  159. package/src/storage/storage.test.ts +0 -274
  160. package/src/store/conformance.test.ts +0 -15
  161. package/src/store/firebase.test.ts +0 -131
  162. package/src/store/firebase.ts +0 -658
  163. package/src/store/index.ts +0 -623
  164. package/src/store/query.test.ts +0 -110
  165. package/src/store/query.ts +0 -113
  166. package/src/store/sqlite.test.ts +0 -218
  167. package/src/store/sqlite.ts +0 -1480
  168. package/src/task-state.test.ts +0 -506
  169. package/src/testing/conformance.ts +0 -319
  170. package/src/testing/index.ts +0 -1
  171. package/src/types/index.ts +0 -859
  172. package/src/use-case-validation.test.ts +0 -324
  173. package/src/utils/fractional-index.test.ts +0 -228
  174. package/src/utils/fractional-index.ts +0 -254
  175. package/src/utils/index.ts +0 -7
  176. package/src/utils/key.test.ts +0 -76
  177. package/src/utils/key.ts +0 -62
  178. package/src/utils/mentions.test.ts +0 -132
  179. package/src/utils/mentions.ts +0 -131
  180. package/src/utils/status.ts +0 -419
  181. package/src/utils/workflow.ts +0 -306
  182. package/src/webhooks/dispatcher.ts +0 -190
  183. package/src/webhooks/index.ts +0 -2
  184. package/src/webhooks/signature.ts +0 -57
  185. package/src/webhooks/webhooks.test.ts +0 -201
  186. package/tsconfig.json +0 -8
  187. package/tsconfig.tsbuildinfo +0 -1
@@ -1,859 +0,0 @@
1
- export type DefaultPriority = 'urgent' | 'high' | 'medium' | 'low' | 'none';
2
- export type Priority = DefaultPriority | (string & {});
3
-
4
- export type DefaultTaskStatus = 'backlog' | 'todo' | 'in_progress' | 'in_review' | 'done' | 'canceled';
5
- export type TaskStatus = DefaultTaskStatus | (string & {});
6
-
7
- export type SemanticStatus = 'not_started' | 'in_progress' | 'completed' | 'canceled';
8
-
9
- export interface StatusDefinition {
10
- key: string;
11
- label: string;
12
- category: SemanticStatus;
13
- }
14
-
15
- export interface TaskDerivedStatus {
16
- semanticStatus: SemanticStatus;
17
- isReady: boolean;
18
- isBlocked: boolean;
19
- blockingTaskIds: string[];
20
- isOverdue: boolean;
21
- isUpcoming: boolean;
22
- isUnplanned: boolean;
23
- isUnassigned: boolean;
24
- isStalled: boolean;
25
- isOverEstimate: boolean;
26
- isPaceWarning: boolean;
27
- isDone: boolean;
28
- isActive: boolean;
29
- isCancelled: boolean;
30
- }
31
-
32
- export type TaskLifecycleState = TaskDerivedStatus;
33
-
34
- export type Role = 'admin' | 'project_manager' | 'contributor' | 'viewer';
35
-
36
- export interface WorkingHoursRange {
37
- start: string; // "09:00" (HH:MM 24-hour format)
38
- end: string; // "17:00"
39
- }
40
-
41
- export interface DaySchedule {
42
- dayOfWeek: number; // 0 = Sunday, 1 = Monday, ..., 6 = Saturday
43
- isWorkingDay: boolean;
44
- hours?: WorkingHoursRange[];
45
- }
46
-
47
- export interface Holiday {
48
- date: string; // "YYYY-MM-DD"
49
- name?: string;
50
- halfDay?: boolean; // if true, counts as 50% working hours
51
- }
52
-
53
- export interface WorkSchedule {
54
- id?: string;
55
- name?: string;
56
- timezone?: string; // Informational (e.g. "UTC", "America/New_York")
57
- defaultHoursPerDay?: number; // Default: 8
58
- days: DaySchedule[];
59
- holidays?: Holiday[];
60
- }
61
-
62
- export interface User {
63
- id: string;
64
- name: string;
65
- email: string;
66
- avatarUrl?: string;
67
- role: Role;
68
- weeklyCapacityHours?: number;
69
- schedule?: WorkSchedule;
70
- createdAt: string;
71
- }
72
-
73
- export interface Team {
74
- id: string;
75
- name: string;
76
- description?: string;
77
- leaderId?: string;
78
- memberIds: string[];
79
- weeklyCapacityHours?: number;
80
- schedule?: WorkSchedule;
81
- /** Tenant that owns the team. Set by the engine from the creating actor. */
82
- tenantId?: string;
83
- createdAt: string;
84
- updatedAt: string;
85
- }
86
-
87
- export interface CustomFieldDefinition {
88
- id: string;
89
- key: string;
90
- label: string;
91
- /** A built-in type, or a type registered by a plugin's `customFieldTypes`. */
92
- type: 'text' | 'number' | 'date' | 'boolean' | 'single_select' | 'multi_select' | 'user' | (string & {});
93
- options?: string[];
94
- required?: boolean;
95
- defaultValue?: unknown;
96
- }
97
-
98
- export interface WorkflowTransition {
99
- id?: string;
100
- name?: string;
101
- fromStatusKey: string | '*';
102
- toStatusKey: string;
103
- }
104
-
105
- export interface TaskTypeDefinition {
106
- key: string;
107
- label: string;
108
- description?: string;
109
- icon?: string;
110
- defaultStatusKey?: string;
111
- workflowId?: string;
112
- }
113
-
114
- export interface Workflow {
115
- id: string;
116
- name: string;
117
- description?: string;
118
- statuses: StatusDefinition[];
119
- transitions: WorkflowTransition[];
120
- taskTypes?: TaskTypeDefinition[];
121
- defaultStatusKey?: string;
122
- isDefault?: boolean;
123
- /** Tenant that owns the workflow. Set by the engine from the creating actor. */
124
- tenantId?: string;
125
- createdAt: string;
126
- updatedAt: string;
127
- }
128
-
129
- export interface Project {
130
- id: string;
131
- key?: string; // e.g. "CP" or "PROJ"
132
- name: string;
133
- description?: string;
134
- ownerId?: string;
135
- /** Project membership and roles, used by role-based authorization policies. */
136
- members?: ProjectMember[];
137
- /** Tenant that owns the project. Set by the engine from the creating actor; never from payloads. */
138
- tenantId?: string;
139
- teamIds?: string[]; // team IDs
140
- workflowId?: string;
141
- workflow?: Workflow;
142
- taskTypes?: TaskTypeDefinition[];
143
- statusDefinitions?: StatusDefinition[];
144
- priorityDefinitions?: Array<{ key: string; label: string; level?: number }>;
145
- customFieldDefinitions?: CustomFieldDefinition[];
146
- schedule?: WorkSchedule;
147
- startDate?: string;
148
- targetEndDate?: string;
149
- createdAt: string;
150
- updatedAt: string;
151
- }
152
-
153
- export interface TaskContainer {
154
- id: string;
155
- projectId: string;
156
- name: string;
157
- description?: string;
158
- parentId?: string; // nested container hierarchy (e.g., folder -> epic -> group)
159
- type?: 'epic' | 'group' | 'section' | 'folder' | string;
160
- color?: string;
161
- createdAt: string;
162
- updatedAt: string;
163
- }
164
-
165
- export interface TaskDependency {
166
- id: string;
167
- taskId: string;
168
- dependsOnTaskId: string;
169
- type: 'blocking' | 'blocked_by' | 'relates_to';
170
- }
171
-
172
- export interface TaskDependencyGraph {
173
- taskId: string;
174
- upstreamTasks: Task[]; // tasks that this task depends on
175
- downstreamTasks: Task[]; // tasks that depend on this task
176
- dependencies: TaskDependency[];
177
- }
178
-
179
- export interface TaskTodoItem {
180
- id: string;
181
- title: string;
182
- completed: boolean;
183
- createdAt?: string;
184
- completedAt?: string;
185
- }
186
-
187
- export interface TaskAssignee {
188
- id: string;
189
- name?: string;
190
- role?: string;
191
- type?: 'user' | 'agent' | 'team';
192
- avatarUrl?: string;
193
- }
194
-
195
- export interface Task {
196
- id: string;
197
- projectId: string;
198
- key?: string; // e.g. "MOB-12"
199
- title: string;
200
- description?: string;
201
- status: TaskStatus;
202
- semanticStatus?: SemanticStatus;
203
- priority: Priority;
204
- taskType?: string; // e.g. "bug", "feature", "task", "epic"
205
- assigneeId?: string;
206
- assignees?: TaskAssignee[];
207
- reporterId?: string;
208
- reviewerId?: string;
209
- iterationId?: string;
210
- teamId?: string;
211
- containerId?: string;
212
- deliverableId?: string; // Direct link to parent deliverable
213
- plannedStartDate?: string;
214
- actualStartDate?: string;
215
- actualEndDate?: string;
216
- completedAt?: string;
217
- dueDate?: string;
218
- // Duration & Effort (in hours and/or minutes)
219
- estimatedHours?: number;
220
- loggedHours?: number;
221
- actualHours?: number;
222
- billableHours?: number;
223
- estimatedDurationMinutes?: number;
224
- actualDurationMinutes?: number;
225
- billableDurationMinutes?: number;
226
- /** Cumulative active execution time spent in 'in_progress' status (in seconds) */
227
- actualDurationSeconds?: number;
228
- /** Transient ISO timestamp marking the start of current 'in_progress' session (null when not in_progress) */
229
- inProgressSince?: string | null;
230
- /** Cumulative duration spent in blocked state while in progress (in seconds) */
231
- blockedDurationSeconds?: number;
232
- /** Transient ISO timestamp marking when the task became blocked while in progress (null when not blocked or not in_progress) */
233
- blockedSince?: string | null;
234
- // Progress (0 to 100 percentage)
235
- progress?: number;
236
- isBlocked?: boolean;
237
- blockedReason?: string | null;
238
- tags?: string[];
239
- todos?: TaskTodoItem[];
240
- customFields?: Record<string, unknown>;
241
- parentId?: string; // Subtask support
242
- createdAt: string;
243
- updatedAt: string;
244
- }
245
-
246
- export type CreateTaskInput = Omit<Task, 'id' | 'createdAt' | 'updatedAt' | 'status' | 'priority'> & {
247
- status?: TaskStatus;
248
- priority?: Priority;
249
- };
250
-
251
- export type DeliverableStatus =
252
- | 'draft'
253
- | 'planned'
254
- | 'in_production'
255
- | 'internal_review'
256
- | 'client_review'
257
- | 'revision_requested'
258
- | 'approved'
259
- | 'delivered'
260
- | 'canceled'
261
- | (string & {});
262
-
263
- export interface Deliverable {
264
- id: string;
265
- projectId: string;
266
- title: string;
267
- description?: string;
268
- status: DeliverableStatus;
269
- format?: string; // e.g., '16:9 4K ProRes', 'Figma', 'PDF'
270
- specs?: Record<string, unknown>; // Technical specifications (resolution, frame rate, etc.)
271
- leadId?: string; // Creative director or lead creator
272
- reviewerId?: string; // Approver or client reviewer
273
- dueDate?: string;
274
- deliveredAt?: string;
275
- outputUrls?: string[]; // Links to final rendered assets, exports, or storage keys
276
- customFields?: Record<string, unknown>;
277
- createdAt: string;
278
- updatedAt: string;
279
- }
280
-
281
- export interface DeliverableSummary {
282
- deliverable: Deliverable;
283
- totalTasks: number;
284
- completedTasks: number;
285
- activeTasks: number;
286
- progressPercentage: number;
287
- estimatedHours: number;
288
- loggedHours: number;
289
- }
290
-
291
- export type CreateDeliverableInput = Omit<Deliverable, 'id' | 'createdAt' | 'updatedAt' | 'status'> & {
292
- status?: DeliverableStatus;
293
- };
294
-
295
- export type CreateProjectInput = Omit<Project, 'id' | 'createdAt' | 'updatedAt'>;
296
-
297
- export interface Iteration {
298
- id: string;
299
- projectId: string;
300
- name: string;
301
- goal?: string;
302
- type?: 'sprint' | 'cycle' | 'milestone' | string;
303
- startDate?: string;
304
- endDate?: string;
305
- status: 'planning' | 'active' | 'completed';
306
- createdAt: string;
307
- }
308
-
309
- export type AuthorType = 'user' | 'agent' | 'system';
310
-
311
- /** The identity a mutation is attributed to (see `CriticalPathEngine.withActor`). */
312
- export interface Actor {
313
- userId: string;
314
- username?: string;
315
- actorType?: AuthorType;
316
- /**
317
- * Tenant the actor belongs to. When set, the actor only sees projects, workflows and teams
318
- * with the same `tenantId`, and everything it creates is stamped with it.
319
- */
320
- tenantId?: string;
321
- /** Workspace-wide roles, e.g. `['admin']`. Interpreted by the authorization policy. */
322
- roles?: string[];
323
- }
324
-
325
- /** A user's role on a project. */
326
- export type ProjectRole = Role;
327
-
328
- export interface ProjectMember {
329
- userId: string;
330
- role: ProjectRole;
331
- }
332
-
333
- export interface CommentReaction {
334
- emoji: string;
335
- userId: string;
336
- createdAt?: string;
337
- }
338
-
339
- export interface Comment {
340
- id: string;
341
- taskId: string;
342
- authorId: string;
343
- authorType?: AuthorType;
344
- parentId?: string; // Threaded reply support
345
- content: string;
346
- mentions?: string[];
347
- reactions?: CommentReaction[];
348
- metadata?: Record<string, unknown>;
349
- createdAt: string;
350
- updatedAt: string;
351
- }
352
-
353
- export interface Attachment {
354
- id: string;
355
- taskId?: string;
356
- projectId?: string;
357
- commentId?: string;
358
- uploaderId: string;
359
- uploaderType?: AuthorType;
360
- filename: string;
361
- mimeType: string;
362
- sizeBytes: number;
363
- url: string;
364
- storageKey?: string;
365
- artifactType?: 'plan' | 'spec' | 'deliverable' | 'review' | 'general';
366
- metadata?: Record<string, unknown>;
367
- createdAt: string;
368
- updatedAt: string;
369
- }
370
-
371
- export type CreateAttachmentInput = Omit<Attachment, 'id' | 'createdAt' | 'updatedAt'>;
372
-
373
- export interface UploadFileInput {
374
- filename: string;
375
- data: Uint8Array | ArrayBuffer | Buffer | Blob | string;
376
- mimeType?: string;
377
- pathPrefix?: string;
378
- encoding?: 'base64' | 'utf-8' | 'binary';
379
- }
380
-
381
- export interface UploadFileResult {
382
- storageKey: string;
383
- url: string;
384
- sizeBytes: number;
385
- mimeType: string;
386
- }
387
-
388
- export interface PresignedUrlOptions {
389
- storageKey: string;
390
- expiresInSeconds?: number;
391
- contentType?: string;
392
- }
393
-
394
- export interface PresignedUploadResult {
395
- uploadUrl: string;
396
- storageKey: string;
397
- method?: 'PUT' | 'POST';
398
- headers?: Record<string, string>;
399
- }
400
-
401
- export interface FileStorageAdapter {
402
- upload(input: UploadFileInput): Promise<UploadFileResult>;
403
- delete(storageKey: string): Promise<boolean>;
404
- download?(storageKey: string): Promise<Buffer | Uint8Array>;
405
- getDownloadUrl?(storageKey: string): Promise<string>;
406
- getPresignedUploadUrl?(options: PresignedUrlOptions): Promise<PresignedUploadResult>;
407
- }
408
-
409
- export interface TimeEntry {
410
- id: string;
411
- taskId: string;
412
- userId: string;
413
- hours: number;
414
- isBillable?: boolean;
415
- description?: string;
416
- loggedAt: string;
417
- }
418
-
419
- export interface Activity {
420
- id: string;
421
- projectId?: string;
422
- taskId?: string;
423
- actorId: string;
424
- action: string;
425
- details: Record<string, unknown>;
426
- createdAt: string;
427
- }
428
-
429
- export interface Webhook {
430
- id: string;
431
- name: string;
432
- url: string;
433
- /** HMAC-SHA256 signing secret. Never returned by engine reads (see `PublicWebhook`). */
434
- secret?: string;
435
- /** Event names to deliver, or `'*'` for every event. */
436
- events: WebhookEvent[];
437
- active: boolean;
438
- /** Tenant whose events this webhook receives. Set from the creating actor. */
439
- tenantId?: string;
440
- createdAt: string;
441
- }
442
-
443
- /** A webhook as returned by engine and API reads: the secret is replaced by `hasSecret`. */
444
- export type PublicWebhook = Omit<Webhook, 'secret'> & { hasSecret: boolean };
445
-
446
- /**
447
- * Webhook subscriptions use domain event names (e.g. `task.created`, `time.logged`); see
448
- * `CriticalPathDomainEvent` in `domain/events.ts`. `'*'` subscribes to everything.
449
- */
450
- export type WebhookEvent = import('../domain/events.js').CriticalPathDomainEvent['name'] | '*';
451
-
452
- /**
453
- * Lifecycle hooks, run in plugin registration order.
454
- *
455
- * - `before*` hooks may transform the input or throw to abort the operation. Their output is
456
- * validated (workflow transitions, custom fields) exactly like caller input, and they cannot
457
- * move a task to another project.
458
- * - `after*` hooks run once the change is stored. Errors are logged and do not fail the call.
459
- */
460
- export interface PluginHooks {
461
- beforeTaskCreate?: (task: Partial<Task>) => Promise<Partial<Task>> | Partial<Task>;
462
- afterTaskCreate?: (task: Task) => Promise<void> | void;
463
- beforeTaskUpdate?: (id: string, updates: Partial<Task>) => Promise<Partial<Task>> | Partial<Task>;
464
- afterTaskUpdate?: (task: Task, previousState: Task) => Promise<void> | void;
465
- beforeTaskDelete?: (id: string, task: Task) => Promise<void> | void;
466
- afterTaskDelete?: (id: string, task: Task) => Promise<void> | void;
467
- }
468
-
469
- /** A custom field type contributed by a plugin, e.g. `url` or `currency`. */
470
- export interface CustomFieldType {
471
- /** The `type` value used in `CustomFieldDefinition`s. Must not clash with a built-in type. */
472
- type: string;
473
- label?: string;
474
- /** Returns an error message for an invalid value, or nothing when valid. Not called for empty values. */
475
- validate: (value: unknown, definition: CustomFieldDefinition) => string | null | undefined | void;
476
- }
477
-
478
- /** Context passed to plugin routes and middleware. */
479
- export interface PluginRequestContext {
480
- /** The engine as the calling actor (authorization and tenancy apply). */
481
- engine: import('../engine/index.js').CriticalPathEngine;
482
- /** The caller resolved by the router's `getContext`, if any. */
483
- context?: Record<string, unknown> & { userId?: string };
484
- url: URL;
485
- /** Path parameters from the route pattern, e.g. `{ projectId: 'p1' }` for `/reports/:projectId`. */
486
- params: Record<string, string>;
487
- }
488
-
489
- export interface PluginRoute {
490
- method: 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';
491
- /** Path below the router's base, with `:name` parameters, e.g. `/reports/:projectId`. */
492
- path: string;
493
- handler: (request: Request, ctx: PluginRequestContext) => Response | Promise<Response>;
494
- }
495
-
496
- /**
497
- * Wraps every routed request (after authentication). Call `next()` to continue, or return a
498
- * `Response` to short-circuit (e.g. rate limiting).
499
- */
500
- export type PluginMiddleware = (
501
- request: Request,
502
- ctx: Omit<PluginRequestContext, 'params'>,
503
- next: () => Promise<Response>
504
- ) => Response | Promise<Response>;
505
-
506
- export interface CriticalPathPlugin {
507
- id: string;
508
- name: string;
509
- version: string;
510
- description?: string;
511
- hooks?: PluginHooks;
512
- /** Additional custom field types projects can use in `customFieldDefinitions`. */
513
- customFieldTypes?: CustomFieldType[];
514
- /** Runs once when the engine starts; `engine.ready` resolves after every plugin's `init`. */
515
- init?: (engine: import('../engine/index.js').CriticalPathEngine) => Promise<void> | void;
516
- /** HTTP routes served by `@critical-path/server`, matched before built-in routes. */
517
- routes?: PluginRoute[];
518
- /** Middleware run by `@critical-path/server` around every routed request. */
519
- middleware?: PluginMiddleware;
520
- }
521
-
522
- export interface CriticalPathConfig {
523
- /**
524
- * Authorization policy applied to every call made through a `withActor` view (which is how
525
- * `@critical-path/server` and the MCP server call the engine). Calls on the base engine are
526
- * trusted. Use `createRolePolicy()` for project-membership roles, or supply your own.
527
- * When omitted, actors may do anything within their tenant.
528
- */
529
- authorize?: AuthorizationPolicy;
530
- /**
531
- * Storage adapter instance, e.g. `new SQLiteStore({ filename: 'app.db' })` or
532
- * `new FirebaseStore({ db })`. Defaults to an `InMemoryStore`.
533
- */
534
- store?: import('../store/index.js').StorageAdapter;
535
- /**
536
- * Your app's user directory: names, weekly capacity and work schedules used by workload and
537
- * capacity calculations. Critical Path does not store users; pass a list, or a function
538
- * (called per calculation, with the calling actor) that loads them from your auth system.
539
- */
540
- users?: User[] | ((actor?: Actor) => User[] | Promise<User[]>);
541
- fileStorage?: FileStorageAdapter;
542
- plugins?: CriticalPathPlugin[];
543
- /** Static webhooks (not stored or editable through the API). */
544
- webhooks?: Omit<Webhook, 'id' | 'createdAt'>[];
545
- /** Delivery behaviour: queue, timeouts, retries, private URL policy, failure callbacks. */
546
- webhookDelivery?: import('../webhooks/dispatcher.js').WebhookDeliveryOptions;
547
- defaultSchedule?: WorkSchedule;
548
- initialData?: {
549
- projects?: Project[];
550
- tasks?: Task[];
551
- /** Added to the user directory (see `CriticalPathConfig.users`). */
552
- users?: User[];
553
- iterations?: Iteration[];
554
- teams?: Team[];
555
- containers?: TaskContainer[];
556
- workflows?: Workflow[];
557
- deliverables?: Deliverable[];
558
- };
559
- }
560
-
561
- // ==========================================
562
- // Ladder of Abstraction Types
563
- // ==========================================
564
-
565
- export type AbstractionLevel = 'macro' | 'standard' | 'concrete' | 'all';
566
-
567
- export type MacroPhaseHealth = 'on_track' | 'at_risk' | 'blocked' | 'overdue' | 'completed';
568
-
569
- export interface MacroPhaseRollup {
570
- id: string; // containerId, iterationId, deliverableId, or 'unassigned'
571
- type: 'container' | 'iteration' | 'deliverable' | 'phase';
572
- name: string;
573
- description?: string;
574
- startDate?: string;
575
- endDate?: string;
576
- durationHours: number;
577
- totalTasks: number;
578
- completedTasks: number;
579
- inProgressTasks: number;
580
- blockedTasks: number;
581
- progressPercentage: number;
582
- totalEstimatedHours: number;
583
- totalLoggedHours: number;
584
- isCritical: boolean;
585
- criticalTaskCount: number;
586
- health: MacroPhaseHealth;
587
- taskIds: string[];
588
- }
589
-
590
- export interface MacroTimelineSummary {
591
- projectId: string;
592
- projectName: string;
593
- overallStartDate?: string;
594
- overallEndDate?: string;
595
- projectedFinishDate?: string;
596
- totalDurationHours: number;
597
- criticalPathDurationHours: number;
598
- overallProgressPercentage: number;
599
- health: MacroPhaseHealth;
600
- totalTasks: number;
601
- completedTasks: number;
602
- inProgressTasks: number;
603
- blockedTasks: number;
604
- totalEstimatedHours: number;
605
- totalLoggedHours: number;
606
- phases: MacroPhaseRollup[];
607
- }
608
-
609
- export interface TaskCriticalPathSchedule {
610
- taskId: string;
611
- earlyStart: number;
612
- earlyFinish: number;
613
- lateStart: number;
614
- lateFinish: number;
615
- totalSlack: number;
616
- isCritical: boolean;
617
- durationHours?: number;
618
- earlyStartDate?: string;
619
- earlyFinishDate?: string;
620
- lateStartDate?: string;
621
- lateFinishDate?: string;
622
- slackWorkingHours?: number;
623
- }
624
-
625
- export interface CriticalPathAnalysis {
626
- projectId: string;
627
- calculatedAt: string;
628
- totalDurationHours: number;
629
- totalWorkingHours?: number;
630
- projectStartDate?: string;
631
- projectEndDate?: string;
632
- criticalTaskIds: string[];
633
- tasks: TaskCriticalPathSchedule[];
634
- }
635
-
636
- export interface ConcreteEvidenceSummary {
637
- attachmentCount: number;
638
- deliverableCount: number;
639
- todoCount: number;
640
- completedTodoCount: number;
641
- timeEntryCount: number;
642
- totalLoggedHours: number;
643
- hasVisualAsset: boolean;
644
- lastActivityAt?: string;
645
- }
646
-
647
- export interface StandardTaskTimelineItem extends Task {
648
- cpm?: TaskCriticalPathSchedule;
649
- blockingTaskIds: string[];
650
- dependentTaskIds: string[];
651
- childTaskIds: string[];
652
- concreteEvidenceSummary: ConcreteEvidenceSummary;
653
- }
654
-
655
- export interface RealityDelta {
656
- plannedStartDate?: string;
657
- actualStartDate?: string;
658
- dueDate?: string;
659
- actualEndDate?: string;
660
- estimatedHours: number;
661
- loggedHours: number;
662
- varianceHours: number; // loggedHours - estimatedHours
663
- effortVarianceHours?: number; // loggedHours - estimatedHours (effort variance)
664
- durationVarianceHours?: number; // actual duration hours - planned duration hours
665
- scheduleVarianceDays?: number; // days difference between planned/due vs actual
666
- scheduleVarianceWorkingDays?: number; // working days difference between planned/due vs actual
667
- accuracyRatio?: number; // loggedHours / estimatedHours (estimation accuracy ratio)
668
- isOverdue: boolean;
669
- isOverEstimate: boolean;
670
- }
671
-
672
- export type ProgressInferenceSource = 'explicit' | 'todos' | 'time_effort' | 'schedule_elapsed' | 'blended';
673
-
674
- export interface TaskProgressInference {
675
- progressPercentage: number;
676
- source: ProgressInferenceSource;
677
- isExplicit: boolean;
678
- breakdown: {
679
- explicitProgress?: number;
680
- todoProgress?: number;
681
- effortProgress?: number;
682
- scheduleProgress?: number;
683
- };
684
- }
685
-
686
- export type ProgressCurveProfile =
687
- | 'linear'
688
- | 's_curve'
689
- | 'early_surge'
690
- | 'late_rush'
691
- | 'stalled'
692
- | 'insufficient_data';
693
-
694
- export interface TaskProgressHistoryPoint {
695
- timestamp: string;
696
- progress: number;
697
- inferredProgress?: number;
698
- status: TaskStatus;
699
- semanticStatus?: SemanticStatus;
700
- action: string;
701
- }
702
-
703
- export interface TaskProgressHistory {
704
- taskId: string;
705
- points: TaskProgressHistoryPoint[];
706
- curveProfile: ProgressCurveProfile;
707
- }
708
-
709
- export interface TaskEVM {
710
- plannedValue: number; // PV (expected hours)
711
- earnedValue: number; // EV (earned hours)
712
- actualCost: number; // AC (logged hours)
713
- costVariance: number; // CV = EV - AC
714
- scheduleVariance: number; // SV = EV - PV
715
- costPerformanceIndex: number; // CPI = EV / AC
716
- schedulePerformanceIndex: number; // SPI = EV / PV
717
- }
718
-
719
- export interface TaskInferredActuals {
720
- actualStartDate?: string;
721
- actualEndDate?: string;
722
- isStartDateInferred: boolean;
723
- isEndDateInferred: boolean;
724
- activeWorkingHours?: number;
725
- /** Calendar elapsed hours between actualStartDate and actualEndDate */
726
- calendarDurationHours?: number;
727
- /** Cumulative active execution duration in seconds */
728
- actualDurationSeconds?: number;
729
- /** Cumulative duration spent in blocked state while in progress (in seconds) */
730
- blockedDurationSeconds?: number;
731
- }
732
-
733
- export interface TaskMetrics {
734
- taskId: string;
735
- inferredActuals: TaskInferredActuals;
736
- realityDelta: RealityDelta;
737
- progress: TaskProgressInference;
738
- evm: TaskEVM;
739
- progressHistory: TaskProgressHistory;
740
- }
741
-
742
- export interface ConcreteTaskEvidence {
743
- taskId: string;
744
- attachments: Attachment[];
745
- deliverables: Deliverable[];
746
- todos: TaskTodoItem[];
747
- timeEntries: TimeEntry[];
748
- dailyEffortDistribution: Array<{ date: string; hours: number }>;
749
- activities: Activity[];
750
- realityDelta: RealityDelta;
751
- evidenceSummary: ConcreteEvidenceSummary;
752
- }
753
-
754
- export interface TimelineLadderOptions {
755
- level?: AbstractionLevel;
756
- containerId?: string;
757
- iterationId?: string;
758
- }
759
-
760
- export interface TimelineLadder {
761
- projectId: string;
762
- generatedAt: string;
763
- level: AbstractionLevel;
764
- macro?: MacroTimelineSummary;
765
- standard?: {
766
- tasks: StandardTaskTimelineItem[];
767
- criticalPathTaskIds: string[];
768
- dependencies: TaskDependency[];
769
- totalDurationHours: number;
770
- };
771
- concrete?: Record<string, ConcreteTaskEvidence>;
772
- }
773
-
774
- export interface TaskLadderView {
775
- taskId: string;
776
- macroPhase?: MacroPhaseRollup;
777
- standard: StandardTaskTimelineItem;
778
- concrete: ConcreteTaskEvidence;
779
- metrics?: TaskMetrics;
780
- }
781
-
782
- export type WorkloadInterval = 'day' | 'week' | 'month';
783
- export type WorkloadGroupBy = 'assignee' | 'team' | 'taskType' | 'priority' | 'status';
784
- export type WorkloadMetric = 'scheduled' | 'logged' | 'remaining' | 'blended';
785
-
786
- export interface WorkloadBucket {
787
- date: string; // ISO date string e.g. "2026-09-14" (start of bucket)
788
- timestamp: number; // Unix timestamp in ms
789
- totalHours: number;
790
- values: Record<string, number>; // Dimension key to hours: { [dimensionKey]: hours }
791
- capacity?: Record<string, number>; // Dimension key to available capacity hours: { [dimensionKey]: capacityHours }
792
- totalCapacity?: number;
793
- utilizationRatio?: number; // totalHours / totalCapacity
794
- }
795
-
796
- export interface WorkloadDistribution {
797
- projectId?: string;
798
- startDate: string;
799
- endDate: string;
800
- interval: WorkloadInterval;
801
- groupBy: WorkloadGroupBy;
802
- metric: WorkloadMetric;
803
- seriesKeys: string[]; // Unique series keys sorted across all buckets
804
- seriesLabels: Record<string, string>; // Human-readable labels e.g. { [key]: "Alice" }
805
- buckets: WorkloadBucket[];
806
- totalHours: number;
807
- totalCapacity?: number;
808
- averageUtilization?: number;
809
- }
810
-
811
- export interface WorkloadDistributionOptions {
812
- startDate?: string;
813
- endDate?: string;
814
- interval?: WorkloadInterval; // default: 'week'
815
- groupBy?: WorkloadGroupBy; // default: 'assignee'
816
- metric?: WorkloadMetric; // default: 'blended'
817
- defaultWeeklyCapacityHours?: number; // default: 40
818
- capacityOverrides?: Record<string, number>; // e.g. { [assigneeOrTeamId]: weeklyCapacityHours }
819
- schedule?: WorkSchedule;
820
- userSchedules?: Record<string, WorkSchedule>;
821
- teamSchedules?: Record<string, WorkSchedule>;
822
- }
823
-
824
- // ==========================================
825
- // Authorization
826
- // ==========================================
827
-
828
- /**
829
- * Operations the engine authorizes. Project-scoped actions are checked against a project;
830
- * `project.create` and `workspace.manage` (workflows, teams, webhooks) are workspace-level.
831
- */
832
- export type AuthorizationAction =
833
- | 'project.read'
834
- | 'project.create'
835
- | 'project.update'
836
- | 'project.delete'
837
- | 'project.manage_members'
838
- | 'task.create'
839
- | 'task.update'
840
- | 'task.delete'
841
- | 'comment.create'
842
- | 'comment.moderate'
843
- | 'attachment.create'
844
- | 'attachment.delete'
845
- | 'time.log'
846
- | 'plan.manage'
847
- | 'workspace.manage';
848
-
849
- export interface AuthorizationRequest {
850
- actor: Actor;
851
- action: AuthorizationAction;
852
- /** The project the action targets, for project-scoped actions. */
853
- project?: Project;
854
- /** The specific record, when relevant (e.g. the comment being edited). */
855
- resource?: { type: 'task' | 'comment' | 'attachment'; ownerId?: string };
856
- }
857
-
858
- export type AuthorizationPolicy = (request: AuthorizationRequest) => boolean | Promise<boolean>;
859
-