@critical-path/core 0.17.0 → 0.19.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.
- package/CHANGELOG.md +23 -0
- package/README.md +71 -0
- package/dist/domain/calendar.d.ts +53 -0
- package/dist/domain/calendar.d.ts.map +1 -0
- package/dist/domain/calendar.js +333 -0
- package/dist/domain/calendar.js.map +1 -0
- package/dist/domain/calendar.test.d.ts +2 -0
- package/dist/domain/calendar.test.d.ts.map +1 -0
- package/dist/domain/calendar.test.js +136 -0
- package/dist/domain/calendar.test.js.map +1 -0
- package/dist/domain/cpm.d.ts +8 -3
- package/dist/domain/cpm.d.ts.map +1 -1
- package/dist/domain/cpm.js +36 -3
- package/dist/domain/cpm.js.map +1 -1
- package/dist/domain/cpm.test.js +53 -0
- package/dist/domain/cpm.test.js.map +1 -1
- package/dist/domain/events.d.ts +10 -2
- package/dist/domain/events.d.ts.map +1 -1
- package/dist/domain/events.js.map +1 -1
- package/dist/domain/index.d.ts +2 -0
- package/dist/domain/index.d.ts.map +1 -1
- package/dist/domain/index.js +2 -0
- package/dist/domain/index.js.map +1 -1
- package/dist/domain/ladder.d.ts +3 -2
- package/dist/domain/ladder.d.ts.map +1 -1
- package/dist/domain/ladder.js +21 -3
- package/dist/domain/ladder.js.map +1 -1
- package/dist/domain/metrics.test.js +5 -4
- package/dist/domain/metrics.test.js.map +1 -1
- package/dist/domain/workload.d.ts +10 -0
- package/dist/domain/workload.d.ts.map +1 -0
- package/dist/domain/workload.js +392 -0
- package/dist/domain/workload.js.map +1 -0
- package/dist/domain/workload.test.d.ts +2 -0
- package/dist/domain/workload.test.d.ts.map +1 -0
- package/dist/domain/workload.test.js +261 -0
- package/dist/domain/workload.test.js.map +1 -0
- package/dist/engine/index.d.ts +5 -2
- package/dist/engine/index.d.ts.map +1 -1
- package/dist/engine/index.js +83 -3
- package/dist/engine/index.js.map +1 -1
- package/dist/store/sqlite.d.ts.map +1 -1
- package/dist/store/sqlite.js +9 -3
- package/dist/store/sqlite.js.map +1 -1
- package/dist/store/sqlite.test.js +15 -1
- package/dist/store/sqlite.test.js.map +1 -1
- package/dist/task-state.test.js +49 -0
- package/dist/task-state.test.js.map +1 -1
- package/dist/types/index.d.ts +81 -1
- package/dist/types/index.d.ts.map +1 -1
- package/dist/utils/status.d.ts.map +1 -1
- package/dist/utils/status.js +5 -2
- package/dist/utils/status.js.map +1 -1
- package/package.json +1 -1
- package/src/domain/calendar.test.ts +164 -0
- package/src/domain/calendar.ts +457 -0
- package/src/domain/cpm.test.ts +61 -0
- package/src/domain/cpm.ts +47 -4
- package/src/domain/events.ts +11 -1
- package/src/domain/index.ts +2 -0
- package/src/domain/ladder.ts +25 -4
- package/src/domain/metrics.test.ts +6 -4
- package/src/domain/workload.test.ts +311 -0
- package/src/domain/workload.ts +457 -0
- package/src/engine/index.ts +103 -5
- package/src/store/sqlite.test.ts +17 -1
- package/src/store/sqlite.ts +11 -1
- package/src/task-state.test.ts +60 -1
- package/src/types/index.ts +89 -0
- package/src/utils/status.ts +7 -2
- package/tsconfig.tsbuildinfo +1 -1
package/src/store/sqlite.ts
CHANGED
|
@@ -132,6 +132,8 @@ export class SQLiteStore implements StorageAdapter {
|
|
|
132
132
|
actualDurationMinutes REAL,
|
|
133
133
|
billableDurationMinutes REAL,
|
|
134
134
|
progress REAL,
|
|
135
|
+
isBlocked INTEGER,
|
|
136
|
+
blockedReason TEXT,
|
|
135
137
|
tags TEXT,
|
|
136
138
|
customFields TEXT,
|
|
137
139
|
parentId TEXT,
|
|
@@ -659,8 +661,9 @@ export class SQLiteStore implements StorageAdapter {
|
|
|
659
661
|
reviewerId, iterationId, teamId, containerId, deliverableId, plannedStartDate, actualStartDate, actualEndDate,
|
|
660
662
|
dueDate, estimatedHours, loggedHours, actualHours, billableHours,
|
|
661
663
|
estimatedDurationMinutes, actualDurationMinutes, billableDurationMinutes, progress,
|
|
664
|
+
isBlocked, blockedReason,
|
|
662
665
|
tags, customFields, parentId, createdAt, updatedAt
|
|
663
|
-
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
666
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
664
667
|
`);
|
|
665
668
|
stmt.run(
|
|
666
669
|
newTask.id,
|
|
@@ -690,6 +693,8 @@ export class SQLiteStore implements StorageAdapter {
|
|
|
690
693
|
newTask.actualDurationMinutes ?? null,
|
|
691
694
|
newTask.billableDurationMinutes ?? null,
|
|
692
695
|
newTask.progress ?? null,
|
|
696
|
+
newTask.isBlocked !== undefined ? (newTask.isBlocked ? 1 : 0) : null,
|
|
697
|
+
newTask.blockedReason ?? null,
|
|
693
698
|
JSON.stringify(newTask.tags || []),
|
|
694
699
|
JSON.stringify(newTask.customFields || {}),
|
|
695
700
|
newTask.parentId || null,
|
|
@@ -716,6 +721,7 @@ export class SQLiteStore implements StorageAdapter {
|
|
|
716
721
|
plannedStartDate = ?, actualStartDate = ?, actualEndDate = ?, dueDate = ?,
|
|
717
722
|
estimatedHours = ?, loggedHours = ?, actualHours = ?, billableHours = ?,
|
|
718
723
|
estimatedDurationMinutes = ?, actualDurationMinutes = ?, billableDurationMinutes = ?, progress = ?,
|
|
724
|
+
isBlocked = ?, blockedReason = ?,
|
|
719
725
|
tags = ?, customFields = ?, parentId = ?, updatedAt = ?
|
|
720
726
|
WHERE id = ?
|
|
721
727
|
`);
|
|
@@ -746,6 +752,8 @@ export class SQLiteStore implements StorageAdapter {
|
|
|
746
752
|
updated.actualDurationMinutes ?? null,
|
|
747
753
|
updated.billableDurationMinutes ?? null,
|
|
748
754
|
updated.progress ?? null,
|
|
755
|
+
updated.isBlocked !== undefined ? (updated.isBlocked ? 1 : 0) : null,
|
|
756
|
+
updated.blockedReason ?? null,
|
|
749
757
|
JSON.stringify(updated.tags || []),
|
|
750
758
|
JSON.stringify(updated.customFields || {}),
|
|
751
759
|
updated.parentId || null,
|
|
@@ -1188,6 +1196,8 @@ export class SQLiteStore implements StorageAdapter {
|
|
|
1188
1196
|
private mapTask(row: any): Task {
|
|
1189
1197
|
return {
|
|
1190
1198
|
...row,
|
|
1199
|
+
isBlocked: row.isBlocked !== null && row.isBlocked !== undefined ? Boolean(row.isBlocked) : undefined,
|
|
1200
|
+
blockedReason: row.blockedReason || undefined,
|
|
1191
1201
|
taskType: row.taskType || undefined,
|
|
1192
1202
|
deliverableId: row.deliverableId || undefined,
|
|
1193
1203
|
tags: row.tags ? JSON.parse(row.tags) : [],
|
package/src/task-state.test.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { describe, it, expect, vi } from 'vitest';
|
|
2
2
|
import { CriticalPathEngine } from './engine/index.js';
|
|
3
3
|
import { deriveTaskLifecycleState } from './utils/status.js';
|
|
4
|
-
import type { Task, StatusDefinition, TaskUnblockedEvent } from './index.js';
|
|
4
|
+
import type { Task, StatusDefinition, TaskBlockedEvent, TaskUnblockedEvent } from './index.js';
|
|
5
5
|
|
|
6
6
|
describe('Task State Behaviour & Dependency Validation', () => {
|
|
7
7
|
const baseTask: Task = {
|
|
@@ -443,5 +443,64 @@ describe('Task State Behaviour & Dependency Validation', () => {
|
|
|
443
443
|
expect(lifecycle?.isBlocked).toBe(false);
|
|
444
444
|
expect(lifecycle?.isReady).toBe(true);
|
|
445
445
|
});
|
|
446
|
+
|
|
447
|
+
it('manages first-class isBlocked and blockedReason independently of workflow status', async () => {
|
|
448
|
+
const engine = new CriticalPathEngine();
|
|
449
|
+
const project = await engine.createProject({ key: 'BLOCK', name: 'First Class Blocking' });
|
|
450
|
+
|
|
451
|
+
const blockedEvents: TaskBlockedEvent[] = [];
|
|
452
|
+
const unblockedEvents: TaskUnblockedEvent[] = [];
|
|
453
|
+
engine.events.subscribe<TaskBlockedEvent>('task.blocked', (evt) => {
|
|
454
|
+
blockedEvents.push(evt);
|
|
455
|
+
});
|
|
456
|
+
engine.events.subscribe<TaskUnblockedEvent>('task.unblocked', (evt) => {
|
|
457
|
+
unblockedEvents.push(evt);
|
|
458
|
+
});
|
|
459
|
+
|
|
460
|
+
// 1. Create a task in 'in_progress' status
|
|
461
|
+
const task = await engine.createTask({
|
|
462
|
+
projectId: project.id,
|
|
463
|
+
title: 'Work on feature',
|
|
464
|
+
status: 'in_progress'
|
|
465
|
+
});
|
|
466
|
+
|
|
467
|
+
let lifecycle = await engine.getTaskLifecycleState(task.id);
|
|
468
|
+
expect(lifecycle?.isBlocked).toBe(false);
|
|
469
|
+
|
|
470
|
+
// 2. Explicitly block the task while keeping status in_progress
|
|
471
|
+
const blockedTask = await engine.updateTask(task.id, {
|
|
472
|
+
isBlocked: true,
|
|
473
|
+
blockedReason: 'Awaiting third-party API key'
|
|
474
|
+
});
|
|
475
|
+
expect(blockedTask?.isBlocked).toBe(true);
|
|
476
|
+
expect(blockedTask?.blockedReason).toBe('Awaiting third-party API key');
|
|
477
|
+
expect(blockedTask?.status).toBe('in_progress');
|
|
478
|
+
|
|
479
|
+
// Verify domain event
|
|
480
|
+
expect(blockedEvents).toHaveLength(1);
|
|
481
|
+
expect(blockedEvents[0].aggregateId).toBe(task.id);
|
|
482
|
+
expect(blockedEvents[0].payload.reason).toBe('Awaiting third-party API key');
|
|
483
|
+
|
|
484
|
+
// Verify lifecycle state
|
|
485
|
+
lifecycle = await engine.getTaskLifecycleState(task.id);
|
|
486
|
+
expect(lifecycle?.isBlocked).toBe(true);
|
|
487
|
+
expect(lifecycle?.isReady).toBe(false);
|
|
488
|
+
|
|
489
|
+
// 3. Unblock the task
|
|
490
|
+
const unblockedTask = await engine.updateTask(task.id, {
|
|
491
|
+
isBlocked: false,
|
|
492
|
+
blockedReason: null
|
|
493
|
+
});
|
|
494
|
+
expect(unblockedTask?.isBlocked).toBe(false);
|
|
495
|
+
expect(unblockedTask?.blockedReason).toBeNull();
|
|
496
|
+
expect(unblockedTask?.status).toBe('in_progress');
|
|
497
|
+
|
|
498
|
+
// Verify domain event
|
|
499
|
+
expect(unblockedEvents).toHaveLength(1);
|
|
500
|
+
expect(unblockedEvents[0].aggregateId).toBe(task.id);
|
|
501
|
+
|
|
502
|
+
lifecycle = await engine.getTaskLifecycleState(task.id);
|
|
503
|
+
expect(lifecycle?.isBlocked).toBe(false);
|
|
504
|
+
});
|
|
446
505
|
});
|
|
447
506
|
});
|
package/src/types/index.ts
CHANGED
|
@@ -33,12 +33,40 @@ export type TaskLifecycleState = TaskDerivedStatus;
|
|
|
33
33
|
|
|
34
34
|
export type Role = 'admin' | 'project_manager' | 'contributor' | 'viewer';
|
|
35
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
|
+
|
|
36
62
|
export interface User {
|
|
37
63
|
id: string;
|
|
38
64
|
name: string;
|
|
39
65
|
email: string;
|
|
40
66
|
avatarUrl?: string;
|
|
41
67
|
role: Role;
|
|
68
|
+
weeklyCapacityHours?: number;
|
|
69
|
+
schedule?: WorkSchedule;
|
|
42
70
|
createdAt: string;
|
|
43
71
|
}
|
|
44
72
|
|
|
@@ -48,6 +76,8 @@ export interface Team {
|
|
|
48
76
|
description?: string;
|
|
49
77
|
leaderId?: string;
|
|
50
78
|
memberIds: string[];
|
|
79
|
+
weeklyCapacityHours?: number;
|
|
80
|
+
schedule?: WorkSchedule;
|
|
51
81
|
createdAt: string;
|
|
52
82
|
updatedAt: string;
|
|
53
83
|
}
|
|
@@ -105,6 +135,9 @@ export interface Project {
|
|
|
105
135
|
statusDefinitions?: StatusDefinition[];
|
|
106
136
|
priorityDefinitions?: Array<{ key: string; label: string; level?: number }>;
|
|
107
137
|
customFieldDefinitions?: CustomFieldDefinition[];
|
|
138
|
+
schedule?: WorkSchedule;
|
|
139
|
+
startDate?: string;
|
|
140
|
+
targetEndDate?: string;
|
|
108
141
|
createdAt: string;
|
|
109
142
|
updatedAt: string;
|
|
110
143
|
}
|
|
@@ -183,6 +216,8 @@ export interface Task {
|
|
|
183
216
|
billableDurationMinutes?: number;
|
|
184
217
|
// Progress (0 to 100 percentage)
|
|
185
218
|
progress?: number;
|
|
219
|
+
isBlocked?: boolean;
|
|
220
|
+
blockedReason?: string | null;
|
|
186
221
|
tags?: string[];
|
|
187
222
|
todos?: TaskTodoItem[];
|
|
188
223
|
customFields?: Record<string, unknown>;
|
|
@@ -369,6 +404,7 @@ export type WebhookEvent =
|
|
|
369
404
|
| 'task.updated'
|
|
370
405
|
| 'task.deleted'
|
|
371
406
|
| 'task.status_changed'
|
|
407
|
+
| 'task.blocked'
|
|
372
408
|
| 'task.unblocked'
|
|
373
409
|
| 'comment.created'
|
|
374
410
|
| 'comment.updated'
|
|
@@ -413,6 +449,7 @@ export interface CriticalPathConfig {
|
|
|
413
449
|
fileStorage?: FileStorageAdapter;
|
|
414
450
|
plugins?: CriticalPathPlugin[];
|
|
415
451
|
webhooks?: Omit<Webhook, 'id' | 'createdAt'>[];
|
|
452
|
+
defaultSchedule?: WorkSchedule;
|
|
416
453
|
initialData?: {
|
|
417
454
|
projects?: Project[];
|
|
418
455
|
tasks?: Task[];
|
|
@@ -481,12 +518,21 @@ export interface TaskCriticalPathSchedule {
|
|
|
481
518
|
lateFinish: number;
|
|
482
519
|
totalSlack: number;
|
|
483
520
|
isCritical: boolean;
|
|
521
|
+
durationHours?: number;
|
|
522
|
+
earlyStartDate?: string;
|
|
523
|
+
earlyFinishDate?: string;
|
|
524
|
+
lateStartDate?: string;
|
|
525
|
+
lateFinishDate?: string;
|
|
526
|
+
slackWorkingHours?: number;
|
|
484
527
|
}
|
|
485
528
|
|
|
486
529
|
export interface CriticalPathAnalysis {
|
|
487
530
|
projectId: string;
|
|
488
531
|
calculatedAt: string;
|
|
489
532
|
totalDurationHours: number;
|
|
533
|
+
totalWorkingHours?: number;
|
|
534
|
+
projectStartDate?: string;
|
|
535
|
+
projectEndDate?: string;
|
|
490
536
|
criticalTaskIds: string[];
|
|
491
537
|
tasks: TaskCriticalPathSchedule[];
|
|
492
538
|
}
|
|
@@ -521,6 +567,7 @@ export interface RealityDelta {
|
|
|
521
567
|
effortVarianceHours?: number; // loggedHours - estimatedHours (effort variance)
|
|
522
568
|
durationVarianceHours?: number; // actual duration hours - planned duration hours
|
|
523
569
|
scheduleVarianceDays?: number; // days difference between planned/due vs actual
|
|
570
|
+
scheduleVarianceWorkingDays?: number; // working days difference between planned/due vs actual
|
|
524
571
|
accuracyRatio?: number; // loggedHours / estimatedHours (estimation accuracy ratio)
|
|
525
572
|
isOverdue: boolean;
|
|
526
573
|
isOverEstimate: boolean;
|
|
@@ -630,3 +677,45 @@ export interface TaskLadderView {
|
|
|
630
677
|
metrics?: TaskMetrics;
|
|
631
678
|
}
|
|
632
679
|
|
|
680
|
+
export type WorkloadInterval = 'day' | 'week' | 'month';
|
|
681
|
+
export type WorkloadGroupBy = 'assignee' | 'team' | 'taskType' | 'priority' | 'status';
|
|
682
|
+
export type WorkloadMetric = 'scheduled' | 'logged' | 'remaining' | 'blended';
|
|
683
|
+
|
|
684
|
+
export interface WorkloadBucket {
|
|
685
|
+
date: string; // ISO date string e.g. "2026-09-14" (start of bucket)
|
|
686
|
+
timestamp: number; // Unix timestamp in ms
|
|
687
|
+
totalHours: number;
|
|
688
|
+
values: Record<string, number>; // Dimension key to hours: { [dimensionKey]: hours }
|
|
689
|
+
capacity?: Record<string, number>; // Dimension key to available capacity hours: { [dimensionKey]: capacityHours }
|
|
690
|
+
totalCapacity?: number;
|
|
691
|
+
utilizationRatio?: number; // totalHours / totalCapacity
|
|
692
|
+
}
|
|
693
|
+
|
|
694
|
+
export interface WorkloadDistribution {
|
|
695
|
+
projectId?: string;
|
|
696
|
+
startDate: string;
|
|
697
|
+
endDate: string;
|
|
698
|
+
interval: WorkloadInterval;
|
|
699
|
+
groupBy: WorkloadGroupBy;
|
|
700
|
+
metric: WorkloadMetric;
|
|
701
|
+
seriesKeys: string[]; // Unique series keys sorted across all buckets
|
|
702
|
+
seriesLabels: Record<string, string>; // Human-readable labels e.g. { [key]: "Alice" }
|
|
703
|
+
buckets: WorkloadBucket[];
|
|
704
|
+
totalHours: number;
|
|
705
|
+
totalCapacity?: number;
|
|
706
|
+
averageUtilization?: number;
|
|
707
|
+
}
|
|
708
|
+
|
|
709
|
+
export interface WorkloadDistributionOptions {
|
|
710
|
+
startDate?: string;
|
|
711
|
+
endDate?: string;
|
|
712
|
+
interval?: WorkloadInterval; // default: 'week'
|
|
713
|
+
groupBy?: WorkloadGroupBy; // default: 'assignee'
|
|
714
|
+
metric?: WorkloadMetric; // default: 'blended'
|
|
715
|
+
defaultWeeklyCapacityHours?: number; // default: 40
|
|
716
|
+
capacityOverrides?: Record<string, number>; // e.g. { [assigneeOrTeamId]: weeklyCapacityHours }
|
|
717
|
+
schedule?: WorkSchedule;
|
|
718
|
+
userSchedules?: Record<string, WorkSchedule>;
|
|
719
|
+
teamSchedules?: Record<string, WorkSchedule>;
|
|
720
|
+
}
|
|
721
|
+
|
package/src/utils/status.ts
CHANGED
|
@@ -88,8 +88,13 @@ export function deriveTaskLifecycleState(
|
|
|
88
88
|
return upstreamDef.category !== 'completed';
|
|
89
89
|
});
|
|
90
90
|
const blockingTaskIds = blockingTasks.map((t) => t.id);
|
|
91
|
-
const
|
|
92
|
-
|
|
91
|
+
const isExplicitlyBlocked = Boolean(
|
|
92
|
+
task.isBlocked === true ||
|
|
93
|
+
task.customFields?.isBlocked === true ||
|
|
94
|
+
task.status === 'blocked'
|
|
95
|
+
);
|
|
96
|
+
const isBlocked = !isDone && (blockingTaskIds.length > 0 || isExplicitlyBlocked);
|
|
97
|
+
const isReady = semanticStatus === 'not_started' && !isBlocked;
|
|
93
98
|
|
|
94
99
|
// Time & Schedule Indicators
|
|
95
100
|
let isOverdue = false;
|
package/tsconfig.tsbuildinfo
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"root":["./src/deliverables.test.ts","./src/index.test.ts","./src/index.ts","./src/status.test.ts","./src/task-state.test.ts","./src/use-case-validation.test.ts","./src/domain/cpm.test.ts","./src/domain/cpm.ts","./src/domain/custom-fields.ts","./src/domain/ddd.test.ts","./src/domain/entities.ts","./src/domain/events.ts","./src/domain/graph.ts","./src/domain/index.ts","./src/domain/ladder.test.ts","./src/domain/ladder.ts","./src/domain/metrics.test.ts","./src/domain/metrics.ts","./src/engine/index.ts","./src/plugins/index.ts","./src/storage/file-storage.ts","./src/storage/firebase-storage.ts","./src/storage/index.ts","./src/storage/s3.ts","./src/storage/storage.test.ts","./src/store/firebase.test.ts","./src/store/firebase.ts","./src/store/index.ts","./src/store/sqlite.test.ts","./src/store/sqlite.ts","./src/types/index.ts","./src/utils/index.ts","./src/utils/key.test.ts","./src/utils/key.ts","./src/utils/mentions.test.ts","./src/utils/mentions.ts","./src/utils/status.ts","./src/utils/workflow.ts"],"version":"5.9.3"}
|
|
1
|
+
{"root":["./src/deliverables.test.ts","./src/index.test.ts","./src/index.ts","./src/status.test.ts","./src/task-state.test.ts","./src/use-case-validation.test.ts","./src/domain/calendar.test.ts","./src/domain/calendar.ts","./src/domain/cpm.test.ts","./src/domain/cpm.ts","./src/domain/custom-fields.ts","./src/domain/ddd.test.ts","./src/domain/entities.ts","./src/domain/events.ts","./src/domain/graph.ts","./src/domain/index.ts","./src/domain/ladder.test.ts","./src/domain/ladder.ts","./src/domain/metrics.test.ts","./src/domain/metrics.ts","./src/domain/workload.test.ts","./src/domain/workload.ts","./src/engine/index.ts","./src/plugins/index.ts","./src/storage/file-storage.ts","./src/storage/firebase-storage.ts","./src/storage/index.ts","./src/storage/s3.ts","./src/storage/storage.test.ts","./src/store/firebase.test.ts","./src/store/firebase.ts","./src/store/index.ts","./src/store/sqlite.test.ts","./src/store/sqlite.ts","./src/types/index.ts","./src/utils/index.ts","./src/utils/key.test.ts","./src/utils/key.ts","./src/utils/mentions.test.ts","./src/utils/mentions.ts","./src/utils/status.ts","./src/utils/workflow.ts"],"version":"5.9.3"}
|