@critical-path/core 0.36.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 (185) hide show
  1. package/package.json +5 -1
  2. package/CHANGELOG.md +0 -593
  3. package/dist/deliverables.test.d.ts +0 -2
  4. package/dist/deliverables.test.d.ts.map +0 -1
  5. package/dist/deliverables.test.js +0 -232
  6. package/dist/deliverables.test.js.map +0 -1
  7. package/dist/domain/calendar.test.d.ts +0 -2
  8. package/dist/domain/calendar.test.d.ts.map +0 -1
  9. package/dist/domain/calendar.test.js +0 -181
  10. package/dist/domain/calendar.test.js.map +0 -1
  11. package/dist/domain/cpm.test.d.ts +0 -2
  12. package/dist/domain/cpm.test.d.ts.map +0 -1
  13. package/dist/domain/cpm.test.js +0 -166
  14. package/dist/domain/cpm.test.js.map +0 -1
  15. package/dist/domain/ddd.test.d.ts +0 -2
  16. package/dist/domain/ddd.test.d.ts.map +0 -1
  17. package/dist/domain/ddd.test.js +0 -349
  18. package/dist/domain/ddd.test.js.map +0 -1
  19. package/dist/domain/ladder.test.d.ts +0 -2
  20. package/dist/domain/ladder.test.d.ts.map +0 -1
  21. package/dist/domain/ladder.test.js +0 -213
  22. package/dist/domain/ladder.test.js.map +0 -1
  23. package/dist/domain/metrics.test.d.ts +0 -2
  24. package/dist/domain/metrics.test.d.ts.map +0 -1
  25. package/dist/domain/metrics.test.js +0 -252
  26. package/dist/domain/metrics.test.js.map +0 -1
  27. package/dist/domain/task-duration.test.d.ts +0 -2
  28. package/dist/domain/task-duration.test.d.ts.map +0 -1
  29. package/dist/domain/task-duration.test.js +0 -307
  30. package/dist/domain/task-duration.test.js.map +0 -1
  31. package/dist/domain/workload.test.d.ts +0 -2
  32. package/dist/domain/workload.test.d.ts.map +0 -1
  33. package/dist/domain/workload.test.js +0 -261
  34. package/dist/domain/workload.test.js.map +0 -1
  35. package/dist/engine/actor.test.d.ts +0 -2
  36. package/dist/engine/actor.test.d.ts.map +0 -1
  37. package/dist/engine/actor.test.js +0 -54
  38. package/dist/engine/actor.test.js.map +0 -1
  39. package/dist/engine/authorization.test.d.ts +0 -2
  40. package/dist/engine/authorization.test.d.ts.map +0 -1
  41. package/dist/engine/authorization.test.js +0 -154
  42. package/dist/engine/authorization.test.js.map +0 -1
  43. package/dist/engine/cascade.test.d.ts +0 -2
  44. package/dist/engine/cascade.test.d.ts.map +0 -1
  45. package/dist/engine/cascade.test.js +0 -99
  46. package/dist/engine/cascade.test.js.map +0 -1
  47. package/dist/engine/config.test.d.ts +0 -2
  48. package/dist/engine/config.test.d.ts.map +0 -1
  49. package/dist/engine/config.test.js +0 -46
  50. package/dist/engine/config.test.js.map +0 -1
  51. package/dist/engine/entity-events.test.d.ts +0 -2
  52. package/dist/engine/entity-events.test.d.ts.map +0 -1
  53. package/dist/engine/entity-events.test.js +0 -61
  54. package/dist/engine/entity-events.test.js.map +0 -1
  55. package/dist/index.test.d.ts +0 -2
  56. package/dist/index.test.d.ts.map +0 -1
  57. package/dist/index.test.js +0 -429
  58. package/dist/index.test.js.map +0 -1
  59. package/dist/plugins/plugins.test.d.ts +0 -2
  60. package/dist/plugins/plugins.test.d.ts.map +0 -1
  61. package/dist/plugins/plugins.test.js +0 -137
  62. package/dist/plugins/plugins.test.js.map +0 -1
  63. package/dist/schemas/schemas.test.d.ts +0 -2
  64. package/dist/schemas/schemas.test.d.ts.map +0 -1
  65. package/dist/schemas/schemas.test.js +0 -58
  66. package/dist/schemas/schemas.test.js.map +0 -1
  67. package/dist/status.test.d.ts +0 -2
  68. package/dist/status.test.d.ts.map +0 -1
  69. package/dist/status.test.js +0 -295
  70. package/dist/status.test.js.map +0 -1
  71. package/dist/storage/storage.test.d.ts +0 -2
  72. package/dist/storage/storage.test.d.ts.map +0 -1
  73. package/dist/storage/storage.test.js +0 -236
  74. package/dist/storage/storage.test.js.map +0 -1
  75. package/dist/storage/upload-limits.test.d.ts +0 -2
  76. package/dist/storage/upload-limits.test.d.ts.map +0 -1
  77. package/dist/storage/upload-limits.test.js +0 -31
  78. package/dist/storage/upload-limits.test.js.map +0 -1
  79. package/dist/store/conformance.test.d.ts +0 -2
  80. package/dist/store/conformance.test.d.ts.map +0 -1
  81. package/dist/store/conformance.test.js +0 -15
  82. package/dist/store/conformance.test.js.map +0 -1
  83. package/dist/store/firebase.test.d.ts +0 -2
  84. package/dist/store/firebase.test.d.ts.map +0 -1
  85. package/dist/store/firebase.test.js +0 -103
  86. package/dist/store/firebase.test.js.map +0 -1
  87. package/dist/store/query.test.d.ts +0 -2
  88. package/dist/store/query.test.d.ts.map +0 -1
  89. package/dist/store/query.test.js +0 -89
  90. package/dist/store/query.test.js.map +0 -1
  91. package/dist/store/sqlite.test.d.ts +0 -2
  92. package/dist/store/sqlite.test.d.ts.map +0 -1
  93. package/dist/store/sqlite.test.js +0 -177
  94. package/dist/store/sqlite.test.js.map +0 -1
  95. package/dist/task-state.test.d.ts +0 -2
  96. package/dist/task-state.test.d.ts.map +0 -1
  97. package/dist/task-state.test.js +0 -423
  98. package/dist/task-state.test.js.map +0 -1
  99. package/dist/use-case-validation.test.d.ts +0 -2
  100. package/dist/use-case-validation.test.d.ts.map +0 -1
  101. package/dist/use-case-validation.test.js +0 -281
  102. package/dist/use-case-validation.test.js.map +0 -1
  103. package/dist/utils/fractional-index.test.d.ts +0 -2
  104. package/dist/utils/fractional-index.test.d.ts.map +0 -1
  105. package/dist/utils/fractional-index.test.js +0 -182
  106. package/dist/utils/fractional-index.test.js.map +0 -1
  107. package/dist/utils/key.test.d.ts +0 -2
  108. package/dist/utils/key.test.d.ts.map +0 -1
  109. package/dist/utils/key.test.js +0 -65
  110. package/dist/utils/key.test.js.map +0 -1
  111. package/dist/utils/mentions.test.d.ts +0 -2
  112. package/dist/utils/mentions.test.d.ts.map +0 -1
  113. package/dist/utils/mentions.test.js +0 -114
  114. package/dist/utils/mentions.test.js.map +0 -1
  115. package/dist/webhooks/webhooks.test.d.ts +0 -2
  116. package/dist/webhooks/webhooks.test.d.ts.map +0 -1
  117. package/dist/webhooks/webhooks.test.js +0 -154
  118. package/dist/webhooks/webhooks.test.js.map +0 -1
  119. package/src/deliverables.test.ts +0 -284
  120. package/src/domain/authorization.ts +0 -82
  121. package/src/domain/calendar.test.ts +0 -216
  122. package/src/domain/calendar.ts +0 -502
  123. package/src/domain/cpm.test.ts +0 -189
  124. package/src/domain/cpm.ts +0 -258
  125. package/src/domain/custom-fields.ts +0 -172
  126. package/src/domain/ddd.test.ts +0 -442
  127. package/src/domain/entities.ts +0 -798
  128. package/src/domain/errors.ts +0 -38
  129. package/src/domain/events.ts +0 -369
  130. package/src/domain/graph.ts +0 -70
  131. package/src/domain/index.ts +0 -12
  132. package/src/domain/ladder.test.ts +0 -251
  133. package/src/domain/ladder.ts +0 -474
  134. package/src/domain/metrics.test.ts +0 -288
  135. package/src/domain/metrics.ts +0 -497
  136. package/src/domain/task-duration.test.ts +0 -354
  137. package/src/domain/workload.test.ts +0 -311
  138. package/src/domain/workload.ts +0 -457
  139. package/src/engine/actor.test.ts +0 -63
  140. package/src/engine/authorization.test.ts +0 -199
  141. package/src/engine/cascade.test.ts +0 -121
  142. package/src/engine/config.test.ts +0 -51
  143. package/src/engine/entity-events.test.ts +0 -67
  144. package/src/engine/index.ts +0 -2495
  145. package/src/index.test.ts +0 -514
  146. package/src/index.ts +0 -9
  147. package/src/plugins/index.ts +0 -103
  148. package/src/plugins/plugins.test.ts +0 -161
  149. package/src/schemas/index.ts +0 -402
  150. package/src/schemas/schemas.test.ts +0 -116
  151. package/src/status.test.ts +0 -354
  152. package/src/storage/file-storage.ts +0 -200
  153. package/src/storage/firebase-storage.ts +0 -209
  154. package/src/storage/index.ts +0 -3
  155. package/src/storage/s3.ts +0 -151
  156. package/src/storage/storage.test.ts +0 -274
  157. package/src/storage/upload-limits.test.ts +0 -41
  158. package/src/store/conformance.test.ts +0 -15
  159. package/src/store/firebase.test.ts +0 -131
  160. package/src/store/firebase.ts +0 -658
  161. package/src/store/index.ts +0 -623
  162. package/src/store/query.test.ts +0 -110
  163. package/src/store/query.ts +0 -113
  164. package/src/store/sqlite.test.ts +0 -218
  165. package/src/store/sqlite.ts +0 -1480
  166. package/src/task-state.test.ts +0 -506
  167. package/src/testing/conformance.ts +0 -319
  168. package/src/testing/index.ts +0 -1
  169. package/src/types/index.ts +0 -871
  170. package/src/use-case-validation.test.ts +0 -324
  171. package/src/utils/fractional-index.test.ts +0 -228
  172. package/src/utils/fractional-index.ts +0 -254
  173. package/src/utils/index.ts +0 -7
  174. package/src/utils/key.test.ts +0 -76
  175. package/src/utils/key.ts +0 -62
  176. package/src/utils/mentions.test.ts +0 -132
  177. package/src/utils/mentions.ts +0 -131
  178. package/src/utils/status.ts +0 -419
  179. package/src/utils/workflow.ts +0 -306
  180. package/src/webhooks/dispatcher.ts +0 -190
  181. package/src/webhooks/index.ts +0 -2
  182. package/src/webhooks/signature.ts +0 -57
  183. package/src/webhooks/webhooks.test.ts +0 -201
  184. package/tsconfig.json +0 -8
  185. package/tsconfig.tsbuildinfo +0 -1
@@ -1,871 +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 UploadLimits {
382
- /** Largest accepted upload in bytes. Applies to direct uploads and declared `sizeBytes`. */
383
- maxBytes?: number;
384
- /**
385
- * Accepted MIME types; entries may end in `/*` (e.g. `image/*`). Applies to uploads, presigned
386
- * uploads and registered attachments. Default: any type.
387
- */
388
- allowedMimeTypes?: string[];
389
- }
390
-
391
- export interface UploadFileResult {
392
- storageKey: string;
393
- url: string;
394
- sizeBytes: number;
395
- mimeType: string;
396
- }
397
-
398
- export interface PresignedUrlOptions {
399
- storageKey: string;
400
- expiresInSeconds?: number;
401
- contentType?: string;
402
- }
403
-
404
- export interface PresignedUploadResult {
405
- uploadUrl: string;
406
- storageKey: string;
407
- method?: 'PUT' | 'POST';
408
- headers?: Record<string, string>;
409
- }
410
-
411
- export interface FileStorageAdapter {
412
- upload(input: UploadFileInput): Promise<UploadFileResult>;
413
- delete(storageKey: string): Promise<boolean>;
414
- download?(storageKey: string): Promise<Buffer | Uint8Array>;
415
- getDownloadUrl?(storageKey: string): Promise<string>;
416
- getPresignedUploadUrl?(options: PresignedUrlOptions): Promise<PresignedUploadResult>;
417
- }
418
-
419
- export interface TimeEntry {
420
- id: string;
421
- taskId: string;
422
- userId: string;
423
- hours: number;
424
- isBillable?: boolean;
425
- description?: string;
426
- loggedAt: string;
427
- }
428
-
429
- export interface Activity {
430
- id: string;
431
- projectId?: string;
432
- taskId?: string;
433
- actorId: string;
434
- action: string;
435
- details: Record<string, unknown>;
436
- createdAt: string;
437
- }
438
-
439
- export interface Webhook {
440
- id: string;
441
- name: string;
442
- url: string;
443
- /** HMAC-SHA256 signing secret. Never returned by engine reads (see `PublicWebhook`). */
444
- secret?: string;
445
- /** Event names to deliver, or `'*'` for every event. */
446
- events: WebhookEvent[];
447
- active: boolean;
448
- /** Tenant whose events this webhook receives. Set from the creating actor. */
449
- tenantId?: string;
450
- createdAt: string;
451
- }
452
-
453
- /** A webhook as returned by engine and API reads: the secret is replaced by `hasSecret`. */
454
- export type PublicWebhook = Omit<Webhook, 'secret'> & { hasSecret: boolean };
455
-
456
- /**
457
- * Webhook subscriptions use domain event names (e.g. `task.created`, `time.logged`); see
458
- * `CriticalPathDomainEvent` in `domain/events.ts`. `'*'` subscribes to everything.
459
- */
460
- export type WebhookEvent = import('../domain/events.js').CriticalPathDomainEvent['name'] | '*';
461
-
462
- /**
463
- * Lifecycle hooks, run in plugin registration order.
464
- *
465
- * - `before*` hooks may transform the input or throw to abort the operation. Their output is
466
- * validated (workflow transitions, custom fields) exactly like caller input, and they cannot
467
- * move a task to another project.
468
- * - `after*` hooks run once the change is stored. Errors are logged and do not fail the call.
469
- */
470
- export interface PluginHooks {
471
- beforeTaskCreate?: (task: Partial<Task>) => Promise<Partial<Task>> | Partial<Task>;
472
- afterTaskCreate?: (task: Task) => Promise<void> | void;
473
- beforeTaskUpdate?: (id: string, updates: Partial<Task>) => Promise<Partial<Task>> | Partial<Task>;
474
- afterTaskUpdate?: (task: Task, previousState: Task) => Promise<void> | void;
475
- beforeTaskDelete?: (id: string, task: Task) => Promise<void> | void;
476
- afterTaskDelete?: (id: string, task: Task) => Promise<void> | void;
477
- }
478
-
479
- /** A custom field type contributed by a plugin, e.g. `url` or `currency`. */
480
- export interface CustomFieldType {
481
- /** The `type` value used in `CustomFieldDefinition`s. Must not clash with a built-in type. */
482
- type: string;
483
- label?: string;
484
- /** Returns an error message for an invalid value, or nothing when valid. Not called for empty values. */
485
- validate: (value: unknown, definition: CustomFieldDefinition) => string | null | undefined | void;
486
- }
487
-
488
- /** Context passed to plugin routes and middleware. */
489
- export interface PluginRequestContext {
490
- /** The engine as the calling actor (authorization and tenancy apply). */
491
- engine: import('../engine/index.js').CriticalPathEngine;
492
- /** The caller resolved by the router's `getContext`, if any. */
493
- context?: Record<string, unknown> & { userId?: string };
494
- url: URL;
495
- /** Path parameters from the route pattern, e.g. `{ projectId: 'p1' }` for `/reports/:projectId`. */
496
- params: Record<string, string>;
497
- }
498
-
499
- export interface PluginRoute {
500
- method: 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';
501
- /** Path below the router's base, with `:name` parameters, e.g. `/reports/:projectId`. */
502
- path: string;
503
- handler: (request: Request, ctx: PluginRequestContext) => Response | Promise<Response>;
504
- }
505
-
506
- /**
507
- * Wraps every routed request (after authentication). Call `next()` to continue, or return a
508
- * `Response` to short-circuit (e.g. rate limiting).
509
- */
510
- export type PluginMiddleware = (
511
- request: Request,
512
- ctx: Omit<PluginRequestContext, 'params'>,
513
- next: () => Promise<Response>
514
- ) => Response | Promise<Response>;
515
-
516
- export interface CriticalPathPlugin {
517
- id: string;
518
- name: string;
519
- version: string;
520
- description?: string;
521
- hooks?: PluginHooks;
522
- /** Additional custom field types projects can use in `customFieldDefinitions`. */
523
- customFieldTypes?: CustomFieldType[];
524
- /** Runs once when the engine starts; `engine.ready` resolves after every plugin's `init`. */
525
- init?: (engine: import('../engine/index.js').CriticalPathEngine) => Promise<void> | void;
526
- /** HTTP routes served by `@critical-path/server`, matched before built-in routes. */
527
- routes?: PluginRoute[];
528
- /** Middleware run by `@critical-path/server` around every routed request. */
529
- middleware?: PluginMiddleware;
530
- }
531
-
532
- export interface CriticalPathConfig {
533
- /**
534
- * Authorization policy applied to every call made through a `withActor` view (which is how
535
- * `@critical-path/server` and the MCP server call the engine). Calls on the base engine are
536
- * trusted. Use `createRolePolicy()` for project-membership roles, or supply your own.
537
- * When omitted, actors may do anything within their tenant.
538
- */
539
- authorize?: AuthorizationPolicy;
540
- /**
541
- * Storage adapter instance, e.g. `new SQLiteStore({ filename: 'app.db' })` or
542
- * `new FirebaseStore({ db })`. Defaults to an `InMemoryStore`.
543
- */
544
- store?: import('../store/index.js').StorageAdapter;
545
- /**
546
- * Your app's user directory: names, weekly capacity and work schedules used by workload and
547
- * capacity calculations. Critical Path does not store users; pass a list, or a function
548
- * (called per calculation, with the calling actor) that loads them from your auth system.
549
- */
550
- users?: User[] | ((actor?: Actor) => User[] | Promise<User[]>);
551
- fileStorage?: FileStorageAdapter;
552
- plugins?: CriticalPathPlugin[];
553
- /** Static webhooks (not stored or editable through the API). */
554
- webhooks?: Omit<Webhook, 'id' | 'createdAt'>[];
555
- /** Limits applied to attachment uploads, presigned uploads and attachment registration. */
556
- uploads?: UploadLimits;
557
- /** Delivery behaviour: queue, timeouts, retries, private URL policy, failure callbacks. */
558
- webhookDelivery?: import('../webhooks/dispatcher.js').WebhookDeliveryOptions;
559
- defaultSchedule?: WorkSchedule;
560
- initialData?: {
561
- projects?: Project[];
562
- tasks?: Task[];
563
- /** Added to the user directory (see `CriticalPathConfig.users`). */
564
- users?: User[];
565
- iterations?: Iteration[];
566
- teams?: Team[];
567
- containers?: TaskContainer[];
568
- workflows?: Workflow[];
569
- deliverables?: Deliverable[];
570
- };
571
- }
572
-
573
- // ==========================================
574
- // Ladder of Abstraction Types
575
- // ==========================================
576
-
577
- export type AbstractionLevel = 'macro' | 'standard' | 'concrete' | 'all';
578
-
579
- export type MacroPhaseHealth = 'on_track' | 'at_risk' | 'blocked' | 'overdue' | 'completed';
580
-
581
- export interface MacroPhaseRollup {
582
- id: string; // containerId, iterationId, deliverableId, or 'unassigned'
583
- type: 'container' | 'iteration' | 'deliverable' | 'phase';
584
- name: string;
585
- description?: string;
586
- startDate?: string;
587
- endDate?: string;
588
- durationHours: number;
589
- totalTasks: number;
590
- completedTasks: number;
591
- inProgressTasks: number;
592
- blockedTasks: number;
593
- progressPercentage: number;
594
- totalEstimatedHours: number;
595
- totalLoggedHours: number;
596
- isCritical: boolean;
597
- criticalTaskCount: number;
598
- health: MacroPhaseHealth;
599
- taskIds: string[];
600
- }
601
-
602
- export interface MacroTimelineSummary {
603
- projectId: string;
604
- projectName: string;
605
- overallStartDate?: string;
606
- overallEndDate?: string;
607
- projectedFinishDate?: string;
608
- totalDurationHours: number;
609
- criticalPathDurationHours: number;
610
- overallProgressPercentage: number;
611
- health: MacroPhaseHealth;
612
- totalTasks: number;
613
- completedTasks: number;
614
- inProgressTasks: number;
615
- blockedTasks: number;
616
- totalEstimatedHours: number;
617
- totalLoggedHours: number;
618
- phases: MacroPhaseRollup[];
619
- }
620
-
621
- export interface TaskCriticalPathSchedule {
622
- taskId: string;
623
- earlyStart: number;
624
- earlyFinish: number;
625
- lateStart: number;
626
- lateFinish: number;
627
- totalSlack: number;
628
- isCritical: boolean;
629
- durationHours?: number;
630
- earlyStartDate?: string;
631
- earlyFinishDate?: string;
632
- lateStartDate?: string;
633
- lateFinishDate?: string;
634
- slackWorkingHours?: number;
635
- }
636
-
637
- export interface CriticalPathAnalysis {
638
- projectId: string;
639
- calculatedAt: string;
640
- totalDurationHours: number;
641
- totalWorkingHours?: number;
642
- projectStartDate?: string;
643
- projectEndDate?: string;
644
- criticalTaskIds: string[];
645
- tasks: TaskCriticalPathSchedule[];
646
- }
647
-
648
- export interface ConcreteEvidenceSummary {
649
- attachmentCount: number;
650
- deliverableCount: number;
651
- todoCount: number;
652
- completedTodoCount: number;
653
- timeEntryCount: number;
654
- totalLoggedHours: number;
655
- hasVisualAsset: boolean;
656
- lastActivityAt?: string;
657
- }
658
-
659
- export interface StandardTaskTimelineItem extends Task {
660
- cpm?: TaskCriticalPathSchedule;
661
- blockingTaskIds: string[];
662
- dependentTaskIds: string[];
663
- childTaskIds: string[];
664
- concreteEvidenceSummary: ConcreteEvidenceSummary;
665
- }
666
-
667
- export interface RealityDelta {
668
- plannedStartDate?: string;
669
- actualStartDate?: string;
670
- dueDate?: string;
671
- actualEndDate?: string;
672
- estimatedHours: number;
673
- loggedHours: number;
674
- varianceHours: number; // loggedHours - estimatedHours
675
- effortVarianceHours?: number; // loggedHours - estimatedHours (effort variance)
676
- durationVarianceHours?: number; // actual duration hours - planned duration hours
677
- scheduleVarianceDays?: number; // days difference between planned/due vs actual
678
- scheduleVarianceWorkingDays?: number; // working days difference between planned/due vs actual
679
- accuracyRatio?: number; // loggedHours / estimatedHours (estimation accuracy ratio)
680
- isOverdue: boolean;
681
- isOverEstimate: boolean;
682
- }
683
-
684
- export type ProgressInferenceSource = 'explicit' | 'todos' | 'time_effort' | 'schedule_elapsed' | 'blended';
685
-
686
- export interface TaskProgressInference {
687
- progressPercentage: number;
688
- source: ProgressInferenceSource;
689
- isExplicit: boolean;
690
- breakdown: {
691
- explicitProgress?: number;
692
- todoProgress?: number;
693
- effortProgress?: number;
694
- scheduleProgress?: number;
695
- };
696
- }
697
-
698
- export type ProgressCurveProfile =
699
- | 'linear'
700
- | 's_curve'
701
- | 'early_surge'
702
- | 'late_rush'
703
- | 'stalled'
704
- | 'insufficient_data';
705
-
706
- export interface TaskProgressHistoryPoint {
707
- timestamp: string;
708
- progress: number;
709
- inferredProgress?: number;
710
- status: TaskStatus;
711
- semanticStatus?: SemanticStatus;
712
- action: string;
713
- }
714
-
715
- export interface TaskProgressHistory {
716
- taskId: string;
717
- points: TaskProgressHistoryPoint[];
718
- curveProfile: ProgressCurveProfile;
719
- }
720
-
721
- export interface TaskEVM {
722
- plannedValue: number; // PV (expected hours)
723
- earnedValue: number; // EV (earned hours)
724
- actualCost: number; // AC (logged hours)
725
- costVariance: number; // CV = EV - AC
726
- scheduleVariance: number; // SV = EV - PV
727
- costPerformanceIndex: number; // CPI = EV / AC
728
- schedulePerformanceIndex: number; // SPI = EV / PV
729
- }
730
-
731
- export interface TaskInferredActuals {
732
- actualStartDate?: string;
733
- actualEndDate?: string;
734
- isStartDateInferred: boolean;
735
- isEndDateInferred: boolean;
736
- activeWorkingHours?: number;
737
- /** Calendar elapsed hours between actualStartDate and actualEndDate */
738
- calendarDurationHours?: number;
739
- /** Cumulative active execution duration in seconds */
740
- actualDurationSeconds?: number;
741
- /** Cumulative duration spent in blocked state while in progress (in seconds) */
742
- blockedDurationSeconds?: number;
743
- }
744
-
745
- export interface TaskMetrics {
746
- taskId: string;
747
- inferredActuals: TaskInferredActuals;
748
- realityDelta: RealityDelta;
749
- progress: TaskProgressInference;
750
- evm: TaskEVM;
751
- progressHistory: TaskProgressHistory;
752
- }
753
-
754
- export interface ConcreteTaskEvidence {
755
- taskId: string;
756
- attachments: Attachment[];
757
- deliverables: Deliverable[];
758
- todos: TaskTodoItem[];
759
- timeEntries: TimeEntry[];
760
- dailyEffortDistribution: Array<{ date: string; hours: number }>;
761
- activities: Activity[];
762
- realityDelta: RealityDelta;
763
- evidenceSummary: ConcreteEvidenceSummary;
764
- }
765
-
766
- export interface TimelineLadderOptions {
767
- level?: AbstractionLevel;
768
- containerId?: string;
769
- iterationId?: string;
770
- }
771
-
772
- export interface TimelineLadder {
773
- projectId: string;
774
- generatedAt: string;
775
- level: AbstractionLevel;
776
- macro?: MacroTimelineSummary;
777
- standard?: {
778
- tasks: StandardTaskTimelineItem[];
779
- criticalPathTaskIds: string[];
780
- dependencies: TaskDependency[];
781
- totalDurationHours: number;
782
- };
783
- concrete?: Record<string, ConcreteTaskEvidence>;
784
- }
785
-
786
- export interface TaskLadderView {
787
- taskId: string;
788
- macroPhase?: MacroPhaseRollup;
789
- standard: StandardTaskTimelineItem;
790
- concrete: ConcreteTaskEvidence;
791
- metrics?: TaskMetrics;
792
- }
793
-
794
- export type WorkloadInterval = 'day' | 'week' | 'month';
795
- export type WorkloadGroupBy = 'assignee' | 'team' | 'taskType' | 'priority' | 'status';
796
- export type WorkloadMetric = 'scheduled' | 'logged' | 'remaining' | 'blended';
797
-
798
- export interface WorkloadBucket {
799
- date: string; // ISO date string e.g. "2026-09-14" (start of bucket)
800
- timestamp: number; // Unix timestamp in ms
801
- totalHours: number;
802
- values: Record<string, number>; // Dimension key to hours: { [dimensionKey]: hours }
803
- capacity?: Record<string, number>; // Dimension key to available capacity hours: { [dimensionKey]: capacityHours }
804
- totalCapacity?: number;
805
- utilizationRatio?: number; // totalHours / totalCapacity
806
- }
807
-
808
- export interface WorkloadDistribution {
809
- projectId?: string;
810
- startDate: string;
811
- endDate: string;
812
- interval: WorkloadInterval;
813
- groupBy: WorkloadGroupBy;
814
- metric: WorkloadMetric;
815
- seriesKeys: string[]; // Unique series keys sorted across all buckets
816
- seriesLabels: Record<string, string>; // Human-readable labels e.g. { [key]: "Alice" }
817
- buckets: WorkloadBucket[];
818
- totalHours: number;
819
- totalCapacity?: number;
820
- averageUtilization?: number;
821
- }
822
-
823
- export interface WorkloadDistributionOptions {
824
- startDate?: string;
825
- endDate?: string;
826
- interval?: WorkloadInterval; // default: 'week'
827
- groupBy?: WorkloadGroupBy; // default: 'assignee'
828
- metric?: WorkloadMetric; // default: 'blended'
829
- defaultWeeklyCapacityHours?: number; // default: 40
830
- capacityOverrides?: Record<string, number>; // e.g. { [assigneeOrTeamId]: weeklyCapacityHours }
831
- schedule?: WorkSchedule;
832
- userSchedules?: Record<string, WorkSchedule>;
833
- teamSchedules?: Record<string, WorkSchedule>;
834
- }
835
-
836
- // ==========================================
837
- // Authorization
838
- // ==========================================
839
-
840
- /**
841
- * Operations the engine authorizes. Project-scoped actions are checked against a project;
842
- * `project.create` and `workspace.manage` (workflows, teams, webhooks) are workspace-level.
843
- */
844
- export type AuthorizationAction =
845
- | 'project.read'
846
- | 'project.create'
847
- | 'project.update'
848
- | 'project.delete'
849
- | 'project.manage_members'
850
- | 'task.create'
851
- | 'task.update'
852
- | 'task.delete'
853
- | 'comment.create'
854
- | 'comment.moderate'
855
- | 'attachment.create'
856
- | 'attachment.delete'
857
- | 'time.log'
858
- | 'plan.manage'
859
- | 'workspace.manage';
860
-
861
- export interface AuthorizationRequest {
862
- actor: Actor;
863
- action: AuthorizationAction;
864
- /** The project the action targets, for project-scoped actions. */
865
- project?: Project;
866
- /** The specific record, when relevant (e.g. the comment being edited). */
867
- resource?: { type: 'task' | 'comment' | 'attachment'; ownerId?: string };
868
- }
869
-
870
- export type AuthorizationPolicy = (request: AuthorizationRequest) => boolean | Promise<boolean>;
871
-