@critical-path/core 0.13.3 → 0.15.0

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 (58) hide show
  1. package/CHANGELOG.md +24 -0
  2. package/README.md +22 -0
  3. package/dist/deliverables.test.js +2 -2
  4. package/dist/deliverables.test.js.map +1 -1
  5. package/dist/domain/entities.d.ts +2 -1
  6. package/dist/domain/entities.d.ts.map +1 -1
  7. package/dist/domain/entities.js +11 -4
  8. package/dist/domain/entities.js.map +1 -1
  9. package/dist/engine/index.d.ts +8 -3
  10. package/dist/engine/index.d.ts.map +1 -1
  11. package/dist/engine/index.js +56 -13
  12. package/dist/engine/index.js.map +1 -1
  13. package/dist/index.test.js +8 -8
  14. package/dist/index.test.js.map +1 -1
  15. package/dist/status.test.d.ts +2 -0
  16. package/dist/status.test.d.ts.map +1 -0
  17. package/dist/status.test.js +199 -0
  18. package/dist/status.test.js.map +1 -0
  19. package/dist/storage/file-storage.d.ts +1 -0
  20. package/dist/storage/file-storage.d.ts.map +1 -1
  21. package/dist/storage/file-storage.js +7 -0
  22. package/dist/storage/file-storage.js.map +1 -1
  23. package/dist/storage/firebase-storage.d.ts +2 -0
  24. package/dist/storage/firebase-storage.d.ts.map +1 -1
  25. package/dist/storage/firebase-storage.js +20 -0
  26. package/dist/storage/firebase-storage.js.map +1 -1
  27. package/dist/storage/storage.test.js +32 -0
  28. package/dist/storage/storage.test.js.map +1 -1
  29. package/dist/store/firebase.test.js +1 -1
  30. package/dist/store/firebase.test.js.map +1 -1
  31. package/dist/store/sqlite.test.js +1 -1
  32. package/dist/store/sqlite.test.js.map +1 -1
  33. package/dist/types/index.d.ts +22 -5
  34. package/dist/types/index.d.ts.map +1 -1
  35. package/dist/use-case-validation.test.js +1 -1
  36. package/dist/use-case-validation.test.js.map +1 -1
  37. package/dist/utils/status.d.ts +7 -10
  38. package/dist/utils/status.d.ts.map +1 -1
  39. package/dist/utils/status.js +104 -21
  40. package/dist/utils/status.js.map +1 -1
  41. package/dist/utils/workflow.js +15 -15
  42. package/dist/utils/workflow.js.map +1 -1
  43. package/package.json +1 -1
  44. package/src/deliverables.test.ts +2 -2
  45. package/src/domain/entities.ts +15 -5
  46. package/src/engine/index.ts +71 -16
  47. package/src/index.test.ts +8 -8
  48. package/src/status.test.ts +226 -0
  49. package/src/storage/file-storage.ts +8 -0
  50. package/src/storage/firebase-storage.ts +20 -0
  51. package/src/storage/storage.test.ts +40 -0
  52. package/src/store/firebase.test.ts +1 -1
  53. package/src/store/sqlite.test.ts +1 -1
  54. package/src/types/index.ts +24 -5
  55. package/src/use-case-validation.test.ts +1 -1
  56. package/src/utils/status.ts +119 -33
  57. package/src/utils/workflow.ts +15 -15
  58. package/tsconfig.tsbuildinfo +1 -1
@@ -79,13 +79,13 @@ export const DEFAULT_VFX_WORKFLOW = {
79
79
  name: 'VFX Production Workflow',
80
80
  description: 'Visual effects production pipeline from bidding and drafting to internal lead review and client supervisor approval.',
81
81
  statuses: [
82
- { key: 'bidding', label: 'Bidding & Draft', completionState: 'not_done', executionState: 'inactive' },
83
- { key: 'awarded', label: 'Awarded / Ready', completionState: 'not_done', executionState: 'inactive' },
84
- { key: 'in_production', label: 'In Production', completionState: 'not_done', executionState: 'active' },
85
- { key: 'internal_review', label: 'Internal Review', completionState: 'not_done', executionState: 'active' },
86
- { key: 'client_review', label: 'Client Review', completionState: 'not_done', executionState: 'active' },
87
- { key: 'revision_requested', label: 'Revision Requested', completionState: 'not_done', executionState: 'active' },
88
- { key: 'approved', label: 'Approved (Final)', completionState: 'done', executionState: 'inactive' },
82
+ { key: 'bidding', label: 'Bidding & Draft', category: 'not_started' },
83
+ { key: 'awarded', label: 'Awarded / Ready', category: 'not_started' },
84
+ { key: 'in_production', label: 'In Production', category: 'in_progress' },
85
+ { key: 'internal_review', label: 'Internal Review', category: 'in_progress' },
86
+ { key: 'client_review', label: 'Client Review', category: 'in_progress' },
87
+ { key: 'revision_requested', label: 'Revision Requested', category: 'in_progress' },
88
+ { key: 'approved', label: 'Approved (Final)', category: 'completed' },
89
89
  DEFAULT_STATUS_DEFINITIONS.canceled
90
90
  ],
91
91
  transitions: [
@@ -114,14 +114,14 @@ export const DEFAULT_CREATIVE_WORKFLOW = {
114
114
  name: 'Creative Production Workflow',
115
115
  description: 'Production pipeline for creative deliverables from briefing and concepts to internal review, client feedback, and final delivery.',
116
116
  statuses: [
117
- { key: 'briefing', label: 'Briefing & Scoping', completionState: 'not_done', executionState: 'inactive' },
118
- { key: 'concept', label: 'Concept & Storyboarding', completionState: 'not_done', executionState: 'active' },
119
- { key: 'in_production', label: 'In Production', completionState: 'not_done', executionState: 'active' },
120
- { key: 'internal_review', label: 'Internal Review', completionState: 'not_done', executionState: 'active' },
121
- { key: 'client_review', label: 'Client Review', completionState: 'not_done', executionState: 'active' },
122
- { key: 'revision_requested', label: 'Revision Requested', completionState: 'not_done', executionState: 'active' },
123
- { key: 'approved', label: 'Approved', completionState: 'done', executionState: 'inactive' },
124
- { key: 'delivered', label: 'Delivered', completionState: 'done', executionState: 'inactive' },
117
+ { key: 'briefing', label: 'Briefing & Scoping', category: 'not_started' },
118
+ { key: 'concept', label: 'Concept & Storyboarding', category: 'in_progress' },
119
+ { key: 'in_production', label: 'In Production', category: 'in_progress' },
120
+ { key: 'internal_review', label: 'Internal Review', category: 'in_progress' },
121
+ { key: 'client_review', label: 'Client Review', category: 'in_progress' },
122
+ { key: 'revision_requested', label: 'Revision Requested', category: 'in_progress' },
123
+ { key: 'approved', label: 'Approved', category: 'completed' },
124
+ { key: 'delivered', label: 'Delivered', category: 'completed' },
125
125
  DEFAULT_STATUS_DEFINITIONS.canceled
126
126
  ],
127
127
  transitions: [
@@ -1 +1 @@
1
- {"version":3,"file":"workflow.js","sourceRoot":"","sources":["../../src/utils/workflow.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"workflow.js","sourceRoot":"","sources":["../../src/utils/workflow.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@critical-path/core",
3
- "version": "0.13.3",
3
+ "version": "0.15.0",
4
4
  "description": "Core headless domain engine, plugin architecture, and data stores for Critical Path",
5
5
  "author": "Jack James",
6
6
  "license": "MIT",
@@ -238,8 +238,8 @@ describe('CriticalPathEngine Deliverables & Rollup Metrics', () => {
238
238
  const summary = await engine.getDeliverableSummary(deliverable.id);
239
239
  expect(summary).not.toBeNull();
240
240
  expect(summary!.totalTasks).toBe(3);
241
- expect(summary!.completedTasks).toBe(1); // 'approved' has completionState 'done'
242
- expect(summary!.activeTasks).toBe(1); // 'in_production' has executionState 'active'
241
+ expect(summary!.completedTasks).toBe(1); // 'approved' has category 'completed'
242
+ expect(summary!.activeTasks).toBe(1); // 'in_production' has category 'in_progress'
243
243
  expect(summary!.estimatedHours).toBe(26); // 8 + 12 + 6
244
244
  expect(summary!.loggedHours).toBe(14); // 8 + 6 + 0
245
245
  expect(summary!.progressPercentage).toBe(50); // (100 + 50 + 0) / 3 = 50%
@@ -11,7 +11,8 @@ import type {
11
11
  CreateProjectInput,
12
12
  Deliverable,
13
13
  DeliverableStatus,
14
- CreateDeliverableInput
14
+ CreateDeliverableInput,
15
+ SemanticStatus
15
16
  } from '../types/index.js';
16
17
  import type {
17
18
  DomainEvent,
@@ -65,6 +66,7 @@ export class TaskEntity extends BaseEntity {
65
66
  public title: string;
66
67
  public description?: string;
67
68
  public status: TaskStatus;
69
+ public semanticStatus?: SemanticStatus;
68
70
  public priority: Priority;
69
71
  public taskType?: string;
70
72
  public assigneeId?: string;
@@ -98,6 +100,7 @@ export class TaskEntity extends BaseEntity {
98
100
  this.title = data.title;
99
101
  this.description = data.description;
100
102
  this.status = data.status;
103
+ this.semanticStatus = data.semanticStatus;
101
104
  this.priority = data.priority;
102
105
  this.taskType = data.taskType;
103
106
  this.assigneeId = data.assigneeId;
@@ -136,12 +139,16 @@ export class TaskEntity extends BaseEntity {
136
139
  validateCustomFieldValues(options.customFieldDefs, input.customFields);
137
140
  }
138
141
 
142
+ const status = input.status || options?.workflow?.defaultStatusKey || 'todo';
143
+ const statusDef = resolveStatusDefinition(status, options?.workflow?.statuses);
144
+
139
145
  const task = new TaskEntity({
140
146
  ...input,
141
147
  id,
142
148
  createdAt: now,
143
149
  updatedAt: now,
144
- status: input.status || options?.workflow?.defaultStatusKey || 'todo',
150
+ status,
151
+ semanticStatus: input.semanticStatus || statusDef.category,
145
152
  priority: input.priority || 'medium',
146
153
  loggedHours: input.loggedHours ?? 0,
147
154
  progress: input.progress ?? 0,
@@ -180,12 +187,14 @@ export class TaskEntity extends BaseEntity {
180
187
  const now = new Date().toISOString();
181
188
 
182
189
  const statusDef = resolveStatusDefinition(newStatus, options?.statusDefs || workflow?.statuses);
183
- if (statusDef.executionState === 'active' && !this.actualStartDate) {
190
+ this.semanticStatus = statusDef.category;
191
+
192
+ if (statusDef.category === 'in_progress' && !this.actualStartDate) {
184
193
  this.actualStartDate = now;
185
194
  }
186
- if (statusDef.completionState === 'done') {
195
+ if (statusDef.category === 'completed' || statusDef.category === 'canceled') {
187
196
  this.actualEndDate = now;
188
- if (this.progress !== undefined && this.progress < 100) {
197
+ if (statusDef.category === 'completed' && this.progress !== undefined && this.progress < 100) {
189
198
  this.progress = 100;
190
199
  }
191
200
  }
@@ -365,6 +374,7 @@ export class TaskEntity extends BaseEntity {
365
374
  title: this.title,
366
375
  description: this.description,
367
376
  status: this.status,
377
+ semanticStatus: this.semanticStatus,
368
378
  priority: this.priority,
369
379
  taskType: this.taskType,
370
380
  assigneeId: this.assigneeId,
@@ -20,11 +20,12 @@ import type {
20
20
  CreateProjectInput,
21
21
  Deliverable,
22
22
  DeliverableSummary,
23
- CreateDeliverableInput
23
+ CreateDeliverableInput,
24
+ TaskLifecycleState
24
25
  } from '../types/index.js';
25
26
  import { StorageAdapter, InMemoryStore } from '../store/index.js';
26
27
  import { PluginRegistry } from '../plugins/index.js';
27
- import { deriveTaskLifecycleState, type TaskLifecycleState, resolveStatusDefinition } from '../utils/status.js';
28
+ import { deriveTaskLifecycleState, resolveStatusDefinition } from '../utils/status.js';
28
29
  import {
29
30
  validateTransition,
30
31
  getAllowedNextStatuses,
@@ -335,16 +336,18 @@ export class CriticalPathEngine {
335
336
  const initialStatus = processedInput.status || taskInput.status || defaultStatus;
336
337
  const now = new Date().toISOString();
337
338
 
338
- // Derive initial lifecycle timestamps
339
+ // Derive initial lifecycle timestamps and semantic status
339
340
  const statusDef = resolveStatusDefinition(initialStatus, project?.statusDefinitions || workflow?.statuses);
340
- const actualStartDate = processedInput.actualStartDate ?? taskInput.actualStartDate ?? (statusDef.executionState === 'active' ? now : undefined);
341
- const actualEndDate = processedInput.actualEndDate ?? taskInput.actualEndDate ?? (statusDef.completionState === 'done' ? now : undefined);
341
+ const semanticStatus = processedInput.semanticStatus ?? taskInput.semanticStatus ?? statusDef.category;
342
+ const actualStartDate = processedInput.actualStartDate ?? taskInput.actualStartDate ?? (statusDef.category === 'in_progress' ? now : undefined);
343
+ const actualEndDate = processedInput.actualEndDate ?? taskInput.actualEndDate ?? ((statusDef.category === 'completed' || statusDef.category === 'canceled') ? now : undefined);
342
344
 
343
345
  const created = await this.store.createTask({
344
346
  projectId,
345
347
  title: processedInput.title || taskInput.title,
346
348
  description: processedInput.description ?? taskInput.description,
347
349
  status: initialStatus,
350
+ semanticStatus,
348
351
  priority: processedInput.priority || taskInput.priority || 'medium',
349
352
  taskType: processedInput.taskType || taskInput.taskType || 'task',
350
353
  assigneeId: processedInput.assigneeId ?? taskInput.assigneeId,
@@ -366,7 +369,7 @@ export class CriticalPathEngine {
366
369
  estimatedDurationMinutes: processedInput.estimatedDurationMinutes ?? taskInput.estimatedDurationMinutes,
367
370
  actualDurationMinutes: processedInput.actualDurationMinutes ?? taskInput.actualDurationMinutes,
368
371
  billableDurationMinutes: processedInput.billableDurationMinutes ?? taskInput.billableDurationMinutes,
369
- progress: processedInput.progress ?? taskInput.progress ?? (statusDef.completionState === 'done' ? 100 : 0),
372
+ progress: processedInput.progress ?? taskInput.progress ?? (statusDef.category === 'completed' ? 100 : 0),
370
373
  tags: processedInput.tags ?? taskInput.tags ?? [],
371
374
  customFields: processedInput.customFields ?? taskInput.customFields ?? {},
372
375
  parentId: processedInput.parentId ?? taskInput.parentId
@@ -428,13 +431,14 @@ export class CriticalPathEngine {
428
431
  processedUpdates.status,
429
432
  project?.statusDefinitions || workflow?.statuses
430
433
  );
434
+ processedUpdates.semanticStatus = processedUpdates.semanticStatus ?? statusDef.category;
431
435
  const now = new Date().toISOString();
432
- if (statusDef.executionState === 'active' && !existing.actualStartDate && !processedUpdates.actualStartDate) {
436
+ if (statusDef.category === 'in_progress' && !existing.actualStartDate && !processedUpdates.actualStartDate) {
433
437
  processedUpdates.actualStartDate = now;
434
438
  }
435
- if (statusDef.completionState === 'done' && !processedUpdates.actualEndDate) {
439
+ if ((statusDef.category === 'completed' || statusDef.category === 'canceled') && !processedUpdates.actualEndDate) {
436
440
  processedUpdates.actualEndDate = now;
437
- if (processedUpdates.progress === undefined && (existing.progress || 0) < 100) {
441
+ if (statusDef.category === 'completed' && processedUpdates.progress === undefined && (existing.progress || 0) < 100) {
438
442
  processedUpdates.progress = 100;
439
443
  }
440
444
  }
@@ -590,13 +594,25 @@ export class CriticalPathEngine {
590
594
  };
591
595
  }
592
596
 
593
- async getTaskLifecycleState(taskId: string): Promise<TaskLifecycleState | null> {
597
+ async getTaskLifecycleState(
598
+ taskId: string,
599
+ options?: { referenceDate?: Date; stalledThresholdDays?: number }
600
+ ): Promise<TaskLifecycleState | null> {
594
601
  const task = await this.getTask(taskId);
595
602
  if (!task) return null;
596
603
  const project = await this.getProject(task.projectId);
597
604
  const workflow = await this.resolveProjectWorkflow(task.projectId);
598
605
  const statusDefs = project?.statusDefinitions || workflow?.statuses;
599
- return deriveTaskLifecycleState(task, statusDefs);
606
+
607
+ const graph = await this.getTaskDependencyGraph(taskId);
608
+ const upstreamTasks = graph.upstreamTasks;
609
+
610
+ return deriveTaskLifecycleState(task, {
611
+ customDefinitions: statusDefs,
612
+ referenceDate: options?.referenceDate,
613
+ stalledThresholdDays: options?.stalledThresholdDays,
614
+ upstreamTasks
615
+ });
600
616
  }
601
617
 
602
618
  // --- Time Tracking ---
@@ -790,8 +806,12 @@ export class CriticalPathEngine {
790
806
  }
791
807
 
792
808
  // --- Attachments ---
793
- async getAttachments(filter?: { taskId?: string; projectId?: string; commentId?: string }): Promise<Attachment[]> {
794
- return this.store.getAttachments(filter);
809
+ async getAttachments(filter?: { taskId?: string; projectId?: string; commentId?: string; artifactType?: string }): Promise<Attachment[]> {
810
+ const attachments = await this.store.getAttachments(filter);
811
+ if (filter?.artifactType) {
812
+ return attachments.filter(a => a.artifactType === filter.artifactType);
813
+ }
814
+ return attachments;
795
815
  }
796
816
 
797
817
  async getAttachment(id: string): Promise<Attachment | null> {
@@ -854,6 +874,7 @@ export class CriticalPathEngine {
854
874
  commentId?: string;
855
875
  uploaderId: string;
856
876
  uploaderType?: 'user' | 'agent' | 'system';
877
+ artifactType?: 'plan' | 'spec' | 'deliverable' | 'review' | 'general';
857
878
  metadata?: Record<string, unknown>;
858
879
  }
859
880
  ): Promise<Attachment> {
@@ -879,10 +900,44 @@ export class CriticalPathEngine {
879
900
  sizeBytes: uploadResult.sizeBytes,
880
901
  url: uploadResult.url,
881
902
  storageKey: uploadResult.storageKey,
903
+ artifactType: input.artifactType,
882
904
  metadata: input.metadata
883
905
  });
884
906
  }
885
907
 
908
+ async readAttachmentText(id: string): Promise<string> {
909
+ const attachment = await this.getAttachment(id);
910
+ if (!attachment) {
911
+ throw new Error(`Attachment with id "${id}" not found.`);
912
+ }
913
+
914
+ if (attachment.storageKey && this.fileStorage && typeof this.fileStorage.download === 'function') {
915
+ const bytes = await this.fileStorage.download(attachment.storageKey);
916
+ return new TextDecoder().decode(bytes);
917
+ }
918
+
919
+ if (attachment.url) {
920
+ if (attachment.url.startsWith('data:')) {
921
+ const commaIndex = attachment.url.indexOf(',');
922
+ const encoded = commaIndex !== -1 ? attachment.url.substring(commaIndex + 1) : attachment.url;
923
+ if (typeof Buffer !== 'undefined') {
924
+ return Buffer.from(encoded, 'base64').toString('utf-8');
925
+ }
926
+ if (typeof atob === 'function') {
927
+ return atob(encoded);
928
+ }
929
+ }
930
+
931
+ const res = await fetch(attachment.url);
932
+ if (!res.ok) {
933
+ throw new Error(`Failed to fetch attachment from URL "${attachment.url}": ${res.statusText}`);
934
+ }
935
+ return await res.text();
936
+ }
937
+
938
+ throw new Error(`Cannot read attachment "${id}": no valid storageKey or URL found.`);
939
+ }
940
+
886
941
  async getPresignedAttachmentUploadUrl(options: PresignedUrlOptions): Promise<PresignedUploadResult> {
887
942
  if (!this.fileStorage || !this.fileStorage.getPresignedUploadUrl) {
888
943
  throw new Error('Presigned uploads are not supported by the configured FileStorageAdapter.');
@@ -1103,9 +1158,9 @@ export class CriticalPathEngine {
1103
1158
 
1104
1159
  for (const task of tasks) {
1105
1160
  const statusDef = resolveStatusDefinition(task.status, project?.statusDefinitions || workflow?.statuses);
1106
- if (statusDef.completionState === 'done') {
1161
+ if (statusDef.category === 'completed') {
1107
1162
  completedTasks++;
1108
- } else if (statusDef.executionState === 'active') {
1163
+ } else if (statusDef.category === 'in_progress') {
1109
1164
  activeTasks++;
1110
1165
  }
1111
1166
 
@@ -1115,7 +1170,7 @@ export class CriticalPathEngine {
1115
1170
  if (typeof task.progress === 'number') {
1116
1171
  totalProgress += task.progress;
1117
1172
  } else {
1118
- totalProgress += statusDef.completionState === 'done' ? 100 : 0;
1173
+ totalProgress += statusDef.category === 'completed' ? 100 : 0;
1119
1174
  }
1120
1175
  }
1121
1176
 
package/src/index.test.ts CHANGED
@@ -128,9 +128,9 @@ describe('CriticalPathEngine Core Tests', () => {
128
128
  key: 'CUST',
129
129
  name: 'Custom Workflow Project',
130
130
  statusDefinitions: [
131
- { key: 'draft', label: 'Draft', completionState: 'not_done', executionState: 'inactive' },
132
- { key: 'active_work', label: 'Active Work', completionState: 'not_done', executionState: 'active' },
133
- { key: 'finished', label: 'Finished', completionState: 'done', executionState: 'inactive' }
131
+ { key: 'draft', label: 'Draft', category: 'not_started' },
132
+ { key: 'active_work', label: 'Active Work', category: 'in_progress' },
133
+ { key: 'finished', label: 'Finished', category: 'completed' }
134
134
  ]
135
135
  });
136
136
 
@@ -145,10 +145,10 @@ describe('CriticalPathEngine Core Tests', () => {
145
145
 
146
146
  const state = await engine.getTaskLifecycleState(task.id);
147
147
  expect(state).not.toBeNull();
148
- expect(state?.completionState).toBe('not_done');
149
- expect(state?.executionState).toBe('active');
148
+ expect(state?.semanticStatus).toBe('in_progress');
150
149
  expect(state?.isActive).toBe(true);
151
150
  expect(state?.isDone).toBe(false);
151
+ expect(state?.isBlocked).toBe(false);
152
152
  });
153
153
 
154
154
  it('builds task dependency graph with upstream and downstream tasks', async () => {
@@ -181,9 +181,9 @@ describe('CriticalPathEngine Core Tests', () => {
181
181
  name: 'Strict Software Workflow',
182
182
  defaultStatusKey: 'backlog',
183
183
  statuses: [
184
- { key: 'backlog', label: 'Backlog', completionState: 'not_done', executionState: 'inactive' },
185
- { key: 'in_progress', label: 'In Progress', completionState: 'not_done', executionState: 'active' },
186
- { key: 'done', label: 'Done', completionState: 'done', executionState: 'inactive' }
184
+ { key: 'backlog', label: 'Backlog', category: 'not_started' },
185
+ { key: 'in_progress', label: 'In Progress', category: 'in_progress' },
186
+ { key: 'done', label: 'Done', category: 'completed' }
187
187
  ],
188
188
  transitions: [
189
189
  { id: 't1', fromStatusKey: 'backlog', toStatusKey: 'in_progress', name: 'Start Work' },
@@ -0,0 +1,226 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { CriticalPathEngine } from './engine/index.js';
3
+ import { resolveStatusDefinition, deriveTaskLifecycleState } from './utils/status.js';
4
+ import type { Task, StatusDefinition } from './types/index.js';
5
+
6
+ describe('Universal Semantic Statuses & Implied Statuses', () => {
7
+ describe('resolveStatusDefinition', () => {
8
+ it('resolves core standard statuses to their semantic category', () => {
9
+ expect(resolveStatusDefinition('todo').category).toBe('not_started');
10
+ expect(resolveStatusDefinition('backlog').category).toBe('not_started');
11
+ expect(resolveStatusDefinition('in_progress').category).toBe('in_progress');
12
+ expect(resolveStatusDefinition('in_review').category).toBe('in_progress');
13
+ expect(resolveStatusDefinition('done').category).toBe('completed');
14
+ expect(resolveStatusDefinition('canceled').category).toBe('canceled');
15
+ });
16
+
17
+ it('resolves custom status definitions when provided', () => {
18
+ const customDefs: StatusDefinition[] = [
19
+ { key: 'concept', label: 'Concept & Brainstorming', category: 'not_started' },
20
+ { key: 'client_review', label: 'Client Feedback Session', category: 'in_progress' },
21
+ { key: 'shipped', label: 'Shipped to Customer', category: 'completed' },
22
+ { key: 'abandoned', label: 'Abandoned Initiative', category: 'canceled' }
23
+ ];
24
+
25
+ expect(resolveStatusDefinition('concept', customDefs).category).toBe('not_started');
26
+ expect(resolveStatusDefinition('client_review', customDefs).category).toBe('in_progress');
27
+ expect(resolveStatusDefinition('shipped', customDefs).category).toBe('completed');
28
+ expect(resolveStatusDefinition('abandoned', customDefs).category).toBe('canceled');
29
+ });
30
+
31
+ it('infers category heuristically when unknown status key is provided', () => {
32
+ expect(resolveStatusDefinition('draft_v2').category).toBe('not_started');
33
+ expect(resolveStatusDefinition('final_approved').category).toBe('completed');
34
+ expect(resolveStatusDefinition('active_development').category).toBe('in_progress');
35
+ expect(resolveStatusDefinition('rejected_proposal').category).toBe('canceled');
36
+ expect(resolveStatusDefinition('custom_arbitrary_key').category).toBe('not_started');
37
+ });
38
+ });
39
+
40
+ describe('deriveTaskLifecycleState', () => {
41
+ const baseTask: Task = {
42
+ id: 'task_1',
43
+ projectId: 'proj_1',
44
+ title: 'Design Wireframes',
45
+ status: 'todo',
46
+ priority: 'high',
47
+ createdAt: '2026-09-01T00:00:00.000Z',
48
+ updatedAt: '2026-09-01T00:00:00.000Z'
49
+ };
50
+
51
+ it('derives basic state for not_started task', () => {
52
+ const derived = deriveTaskLifecycleState(baseTask);
53
+ expect(derived.semanticStatus).toBe('not_started');
54
+ expect(derived.isActive).toBe(false);
55
+ expect(derived.isDone).toBe(false);
56
+ expect(derived.isCancelled).toBe(false);
57
+ expect(derived.isReady).toBe(true);
58
+ expect(derived.isBlocked).toBe(false);
59
+ expect(derived.isUnassigned).toBe(true);
60
+ expect(derived.isUnplanned).toBe(true);
61
+ });
62
+
63
+ it('derives blocked and ready states based on upstream tasks', () => {
64
+ const upstream1: Task = {
65
+ ...baseTask,
66
+ id: 'task_up1',
67
+ status: 'in_progress',
68
+ semanticStatus: 'in_progress'
69
+ };
70
+ const upstream2: Task = {
71
+ ...baseTask,
72
+ id: 'task_up2',
73
+ status: 'done',
74
+ semanticStatus: 'completed'
75
+ };
76
+
77
+ // When upstream1 is in progress, task_1 is blocked
78
+ const blockedState = deriveTaskLifecycleState(baseTask, {
79
+ upstreamTasks: [upstream1, upstream2]
80
+ });
81
+ expect(blockedState.isBlocked).toBe(true);
82
+ expect(blockedState.isReady).toBe(false);
83
+ expect(blockedState.blockingTaskIds).toEqual(['task_up1']);
84
+
85
+ // When all upstream tasks are completed, task_1 becomes ready
86
+ const allDoneState = deriveTaskLifecycleState(baseTask, {
87
+ upstreamTasks: [
88
+ { ...upstream1, status: 'done', semanticStatus: 'completed' },
89
+ upstream2
90
+ ]
91
+ });
92
+ expect(allDoneState.isBlocked).toBe(false);
93
+ expect(allDoneState.isReady).toBe(true);
94
+ expect(allDoneState.blockingTaskIds).toHaveLength(0);
95
+ });
96
+
97
+ it('derives schedule indicators: overdue, upcoming, unplanned', () => {
98
+ const refDate = new Date('2026-09-10T12:00:00.000Z');
99
+
100
+ // Overdue task
101
+ const overdueTask: Task = {
102
+ ...baseTask,
103
+ dueDate: '2026-09-08T00:00:00.000Z'
104
+ };
105
+ const overdueDerived = deriveTaskLifecycleState(overdueTask, { referenceDate: refDate });
106
+ expect(overdueDerived.isOverdue).toBe(true);
107
+ expect(overdueDerived.isUnplanned).toBe(false);
108
+
109
+ // Completed task is not overdue even if dueDate is past
110
+ const completedTask: Task = {
111
+ ...overdueTask,
112
+ status: 'done'
113
+ };
114
+ const completedDerived = deriveTaskLifecycleState(completedTask, { referenceDate: refDate });
115
+ expect(completedDerived.isOverdue).toBe(false);
116
+ expect(completedDerived.isDone).toBe(true);
117
+
118
+ // Upcoming task
119
+ const upcomingTask: Task = {
120
+ ...baseTask,
121
+ plannedStartDate: '2026-09-12T00:00:00.000Z' // within 3 days of Sept 10
122
+ };
123
+ const upcomingDerived = deriveTaskLifecycleState(upcomingTask, { referenceDate: refDate });
124
+ expect(upcomingDerived.isUpcoming).toBe(true);
125
+ });
126
+
127
+ it('derives resource indicators: unassigned and stalled', () => {
128
+ const refDate = new Date('2026-09-15T12:00:00.000Z');
129
+
130
+ // Assigned via assigneeId
131
+ const assignedTask1: Task = {
132
+ ...baseTask,
133
+ assigneeId: 'user_alice'
134
+ };
135
+ expect(deriveTaskLifecycleState(assignedTask1).isUnassigned).toBe(false);
136
+
137
+ // Assigned via assignees array
138
+ const assignedTask2: Task = {
139
+ ...baseTask,
140
+ assignees: [{ id: 'user_bob' }]
141
+ };
142
+ expect(deriveTaskLifecycleState(assignedTask2).isUnassigned).toBe(false);
143
+
144
+ // Stalled task: in_progress with no update in > 7 days
145
+ const stalledTask: Task = {
146
+ ...baseTask,
147
+ status: 'in_progress',
148
+ updatedAt: '2026-09-01T00:00:00.000Z'
149
+ };
150
+ const stalledDerived = deriveTaskLifecycleState(stalledTask, { referenceDate: refDate, stalledThresholdDays: 7 });
151
+ expect(stalledDerived.isStalled).toBe(true);
152
+
153
+ // Not stalled if updated recently
154
+ const activeTask: Task = {
155
+ ...stalledTask,
156
+ updatedAt: '2026-09-14T00:00:00.000Z'
157
+ };
158
+ expect(deriveTaskLifecycleState(activeTask, { referenceDate: refDate, stalledThresholdDays: 7 }).isStalled).toBe(false);
159
+ });
160
+
161
+ it('derives estimate indicators: isOverEstimate and isPaceWarning', () => {
162
+ // Over estimate by logged hours
163
+ const overEstimateTask: Task = {
164
+ ...baseTask,
165
+ status: 'in_progress',
166
+ estimatedHours: 10,
167
+ loggedHours: 12
168
+ };
169
+ const overEstDerived = deriveTaskLifecycleState(overEstimateTask);
170
+ expect(overEstDerived.isOverEstimate).toBe(true);
171
+
172
+ // Pace warning: in_progress task that has been active longer than estimated duration
173
+ const refDate = new Date('2026-09-10T00:00:00.000Z');
174
+ const paceWarningTask: Task = {
175
+ ...baseTask,
176
+ status: 'in_progress',
177
+ actualStartDate: '2026-09-01T00:00:00.000Z', // 9 days = 216 hours elapsed
178
+ estimatedHours: 40 // only 40 hours estimated
179
+ };
180
+ const paceDerived = deriveTaskLifecycleState(paceWarningTask, { referenceDate: refDate });
181
+ expect(paceDerived.isPaceWarning).toBe(true);
182
+ });
183
+ });
184
+
185
+ describe('Engine Integration', () => {
186
+ it('computes full lifecycle state with dependency graph integration', async () => {
187
+ const engine = new CriticalPathEngine();
188
+ const proj = await engine.createProject({ key: 'LIFECYCLE', name: 'Lifecycle Test' });
189
+
190
+ const taskA = await engine.createTask({
191
+ projectId: proj.id,
192
+ title: 'Task A (Dependency)',
193
+ status: 'todo',
194
+ priority: 'high'
195
+ });
196
+
197
+ const taskB = await engine.createTask({
198
+ projectId: proj.id,
199
+ title: 'Task B (Dependent)',
200
+ status: 'todo',
201
+ priority: 'medium'
202
+ });
203
+
204
+ await engine.store.addDependency({
205
+ taskId: taskB.id,
206
+ dependsOnTaskId: taskA.id,
207
+ type: 'blocking'
208
+ });
209
+
210
+ // Task B should be blocked by Task A
211
+ let stateB = await engine.getTaskLifecycleState(taskB.id);
212
+ expect(stateB?.isBlocked).toBe(true);
213
+ expect(stateB?.isReady).toBe(false);
214
+ expect(stateB?.blockingTaskIds).toEqual([taskA.id]);
215
+
216
+ // Complete Task A
217
+ await engine.updateTask(taskA.id, { status: 'done' });
218
+
219
+ // Task B should now be ready
220
+ stateB = await engine.getTaskLifecycleState(taskB.id);
221
+ expect(stateB?.isBlocked).toBe(false);
222
+ expect(stateB?.isReady).toBe(true);
223
+ expect(stateB?.blockingTaskIds).toEqual([]);
224
+ });
225
+ });
226
+ });
@@ -123,6 +123,14 @@ export class InMemoryFileStore implements FileStorageAdapter {
123
123
  return this.files.delete(storageKey);
124
124
  }
125
125
 
126
+ async download(storageKey: string): Promise<Buffer | Uint8Array> {
127
+ const file = this.files.get(storageKey);
128
+ if (!file) {
129
+ throw new Error(`File with storageKey "${storageKey}" not found`);
130
+ }
131
+ return file.data;
132
+ }
133
+
126
134
  async getDownloadUrl(storageKey: string): Promise<string> {
127
135
  const file = this.files.get(storageKey);
128
136
  if (!file) {