@bernierllc/work-item-core
v0.1.4
Published
Universal work item management with configurable types, statuses, maturity levels, dependency tracking, and hierarchical relationships
Readme
@bernierllc/work-item-core
A comprehensive TypeScript library for managing work items with hierarchical relationships, dependency tracking, maturity progression, and status management.
Installation
npm install @bernierllc/work-item-coreFeatures
- Complete CRUD Operations - Create, read, update, delete work items
- Hierarchical Relationships - Parent/child relationships with tree traversal
- Dependency Management - Track dependencies with circular detection (DFS algorithm)
- Blocking Detection - Identify blocking items using BFS-style traversal
- Maturity Progression - State machine for work item maturity levels
- Status Management - Track work item status through lifecycle
- Assignment Management - Assign work items to team members or agents
- Readiness Checks - Determine if work items are ready to start
- Query & Filtering - Powerful filtering, sorting, and pagination
- Batch Operations - Efficient bulk create and update operations
- Statistics & Reporting - Comprehensive project analytics
- Storage Abstraction - Pluggable storage backend (memory included for testing)
Quick Start
import { WorkItemManager, MemoryWorkItemStorage } from '@bernierllc/work-item-core';
// Initialize with in-memory storage
const storage = new MemoryWorkItemStorage();
const manager = new WorkItemManager(storage);
// Create a work item
const result = await manager.create({
project_id: 'proj_123',
title: 'Implement user authentication',
work_type_id: 'type_feature',
maturity_level_id: 'maturity_planned',
status_id: 'status_open',
priority: 8
});
if (result.success) {
console.log('Created work item:', result.data);
}Core Concepts
Work Item
A work item represents a unit of work in a project. Each work item has:
- Identity:
id,project_id,title,description - Classification:
work_type_id(feature, bug, refactor, documentation, chore) - Maturity:
maturity_level_id(idea → discovery → planned → ready → active → complete) - Status:
status_id(open, blocked, in-progress, in-review, done, cancelled) - Priority:
priority(1-10, higher = more important) - Relationships:
parent_work_item_id,depends_on_work_item_ids - Assignment:
assigned_to(team member or agent identifier) - Metadata:
created_at,updated_at,created_from_session_id
Maturity Levels
Work items progress through maturity levels:
- idea - Initial concept
- discovery - Research and investigation
- planned - Defined and estimated
- ready - Ready to start work
- active - Work in progress
- complete - Finished and verified
Work Types
- feature - New functionality
- bug - Defect or issue
- refactor - Code improvement
- documentation - Documentation work
- chore - Maintenance tasks
Statuses
- open - Not yet started
- blocked - Cannot proceed (waiting on dependencies)
- in-progress - Actively being worked on
- in-review - Under review
- done - Completed successfully
- cancelled - Work abandoned
Usage Examples
Creating Work Items
// Create a simple work item
const result = await manager.create({
project_id: 'proj_123',
title: 'Add login form',
work_type_id: 'type_feature',
maturity_level_id: 'maturity_planned',
status_id: 'status_open',
priority: 5
});
// Create with dependencies
const dependent = await manager.create({
project_id: 'proj_123',
title: 'Add logout button',
depends_on_work_item_ids: [result.data!.id],
priority: 3
});
// Create batch
const batch = await manager.createBatch([
{ project_id: 'proj_123', title: 'Task 1', priority: 5 },
{ project_id: 'proj_123', title: 'Task 2', priority: 4 },
{ project_id: 'proj_123', title: 'Task 3', priority: 3 }
]);Hierarchical Relationships
// Create parent work item
const epic = await manager.create({
project_id: 'proj_123',
title: 'User Management Epic',
work_type_id: 'type_feature',
priority: 10
});
// Create child work items
const story1 = await manager.create({
project_id: 'proj_123',
title: 'User login',
parent_work_item_id: epic.data!.id,
priority: 8
});
const story2 = await manager.create({
project_id: 'proj_123',
title: 'User registration',
parent_work_item_id: epic.data!.id,
priority: 7
});
// Get all children
const children = await manager.getChildren(epic.data!.id, false); // Direct children only
const allDescendants = await manager.getChildren(epic.data!.id, true); // Recursive
// Get ancestors
const ancestors = await manager.getAncestors(story1.data!.id);
// Move work item to different parent
await manager.move(story1.data!.id, 'other_epic_id');Dependency Management
// Add dependency
await manager.addDependency('work_item_1', 'work_item_2'); // 1 depends on 2
// Remove dependency
await manager.removeDependency('work_item_1', 'work_item_2');
// Get dependencies
const deps = await manager.getDependencies('work_item_1', false); // Direct only
const allDeps = await manager.getDependencies('work_item_1', true); // Transitive
// Get blocked items (items waiting for this one)
const blockedItems = await manager.getBlockedItems('work_item_1');
// Check for circular dependencies
const circularCheck = await manager.checkCircularDependencies(
'work_item_1',
'work_item_2'
);
if (!circularCheck.valid) {
console.log('Circular dependency detected:', circularCheck.cycle);
}
// Validate all dependencies
const validation = await manager.validateDependencies('work_item_1');
if (!validation.valid) {
console.log('Invalid dependencies:', validation.missing_dependencies);
}Status Management
// Update status
await manager.updateStatus('work_item_1', 'status_in_progress');
// Status transitions are validated
const result = await manager.updateStatus('work_item_1', 'status_done');
if (!result.success) {
console.log('Status update failed:', result.error);
}Maturity Progression
// Promote to next maturity level
const promoted = await manager.promoteMaturity('work_item_1');
if (!promoted.success) {
console.log('Cannot promote:', promoted.error);
}
// Promote to specific level
await manager.promoteMaturity('work_item_1', 'maturity_ready');
// Check if promotion is allowed
const canPromote = await manager.canPromote('work_item_1', 'maturity_active');
if (!canPromote.valid) {
console.log('Cannot promote:', canPromote.reason);
}Assignment Management
// Assign to team member
await manager.assign('work_item_1', 'user:[email protected]');
// Assign to agent
await manager.assign('work_item_1', 'agent:claude');
// Unassign
await manager.unassign('work_item_1');
// Get all assigned items for a person
const assigned = await manager.getAssignedItems('user:[email protected]', {
status_ids: ['status_in_progress']
});Readiness Checks
// Check if work item is ready to start
const readiness = await manager.isReadyToStart('work_item_1');
if (readiness.ready) {
console.log('Ready to start!');
} else {
console.log('Blocking reasons:', readiness.blocking_reasons);
}Querying Work Items
// Query with filters
const results = await manager.query(
{
project_id: 'proj_123',
work_type_ids: ['type_feature', 'type_bug'],
maturity_level_ids: ['maturity_ready', 'maturity_active'],
status_ids: ['status_open', 'status_in_progress'],
priority_min: 5,
priority_max: 10,
blocks_project: true,
assigned_to: 'user:[email protected]',
has_dependencies: false,
is_blocked: false
},
{
sort_by: 'priority',
sort_order: 'desc',
limit: 20,
offset: 0
}
);
// Get unassigned high-priority items
const unassigned = await manager.query({
project_id: 'proj_123',
assigned_to: null,
priority_min: 8
});
// Get root items (no parent)
const rootItems = await manager.query({
project_id: 'proj_123',
parent_work_item_id: null
});Statistics & Reporting
// Get project statistics
const stats = await manager.getStatistics('proj_123');
console.log('Total items:', stats.total_count);
console.log('By work type:', stats.by_work_type);
console.log('By maturity:', stats.by_maturity_level);
console.log('By status:', stats.by_status);
console.log('By priority:', stats.by_priority);
console.log('Assigned:', stats.assigned_count);
console.log('Unassigned:', stats.unassigned_count);
console.log('Ready to start:', stats.ready_count);
console.log('Blocked:', stats.blocked_count);
// Get dependency graph
const graph = await manager.getDependencyGraph({
project_id: 'proj_123'
});
console.log('Nodes:', graph.nodes.length);
console.log('Edges:', graph.edges.length);Batch Operations
// Create multiple items efficiently
const created = await manager.createBatch([
{
project_id: 'proj_123',
title: 'Feature 1',
priority: 8
},
{
project_id: 'proj_123',
title: 'Feature 2',
priority: 7
}
]);
// Update multiple items
const updated = await manager.updateBatch([
{
id: 'item_1',
updates: { priority: 10, assigned_to: 'user:[email protected]' }
},
{
id: 'item_2',
updates: { status_id: 'status_in_progress' }
}
]);
console.log(`Created ${created.successful.length} items`);
console.log(`Updated ${updated.successful.length} items`);
if (created.failed.length > 0) {
console.log('Failures:', created.failed);
}Custom Storage Backend
Implement the WorkItemStorage interface for your database:
import { WorkItemStorage, WorkItem } from '@bernierllc/work-item-core';
class PostgresWorkItemStorage implements WorkItemStorage {
async saveWorkItem(workItem: WorkItem): Promise<void> {
// Save to PostgreSQL
}
async getWorkItem(id: string): Promise<WorkItem | null> {
// Retrieve from PostgreSQL
}
async deleteWorkItem(id: string): Promise<void> {
// Delete from PostgreSQL
}
async queryWorkItems(
filters: WorkItemFilters,
options?: WorkItemQueryOptions
): Promise<WorkItem[]> {
// Query PostgreSQL with filters
}
// Implement remaining methods...
}
// Use custom storage
const storage = new PostgresWorkItemStorage();
const manager = new WorkItemManager(storage);API Reference
WorkItemManager
Constructor
constructor(
storage: WorkItemStorage,
config?: {
maturityLevels?: MaturityLevel[];
statuses?: WorkItemStatus[];
workTypes?: WorkType[];
}
)CRUD Operations
create(input: CreateWorkItemInput): Promise<WorkItemResult<WorkItem>>get(workItemId: string, include_details?: boolean): Promise<WorkItemResult<WorkItem>>update(workItemId: string, updates: UpdateWorkItemInput): Promise<WorkItemResult<WorkItem>>delete(workItemId: string): Promise<WorkItemResult<void>>exists(workItemId: string): Promise<boolean>query(filters: WorkItemFilters, options?: WorkItemQueryOptions): Promise<WorkItem[]>
Hierarchy Management
getChildren(workItemId: string, recursive?: boolean): Promise<WorkItem[]>getAncestors(workItemId: string): Promise<WorkItem[]>move(workItemId: string, newParentId: string | null): Promise<WorkItemResult<WorkItem>>
Dependency Management
addDependency(workItemId: string, dependsOnId: string): Promise<WorkItemResult<WorkItem>>removeDependency(workItemId: string, dependsOnId: string): Promise<WorkItemResult<WorkItem>>getDependencies(workItemId: string, recursive?: boolean): Promise<WorkItem[]>getBlockedItems(workItemId: string): Promise<WorkItem[]>checkCircularDependencies(workItemId: string, dependsOnId: string): Promise<DependencyValidationResult>validateDependencies(workItemId: string): Promise<DependencyValidationResult>
Status & Maturity
updateStatus(workItemId: string, statusId: string): Promise<WorkItemResult<WorkItem>>promoteMaturity(workItemId: string, maturityId?: string): Promise<WorkItemResult<WorkItem>>canPromote(workItemId: string, maturityId: string): Promise<ValidationResult>
Assignment
assign(workItemId: string, assignee: string): Promise<WorkItemResult<WorkItem>>unassign(workItemId: string): Promise<WorkItemResult<WorkItem>>getAssignedItems(assignee: string, filters?: WorkItemFilters): Promise<WorkItem[]>
Readiness & Validation
isReadyToStart(workItemId: string): Promise<ReadinessResult>validate(workItem: WorkItem | CreateWorkItemInput): Promise<ValidationResult>
Batch Operations
createBatch(inputs: CreateWorkItemInput[]): Promise<BatchResult<WorkItem>>updateBatch(updates: Array<{ id: string; updates: UpdateWorkItemInput }>): Promise<BatchResult<WorkItem>>
Statistics & Reporting
getStatistics(projectId: string): Promise<WorkItemStatistics>getDependencyGraph(filters: WorkItemFilters): Promise<DependencyGraph>
Configuration
Custom Maturity Levels
const customMaturityLevels = [
{ id: 'backlog', name: 'Backlog', order: 1 },
{ id: 'sprint', name: 'In Sprint', order: 2 },
{ id: 'done', name: 'Done', order: 3 }
];
const manager = new WorkItemManager(storage, {
maturityLevels: customMaturityLevels
});Custom Statuses
const customStatuses = [
{ id: 'todo', name: 'To Do', category: 'not_started' },
{ id: 'doing', name: 'Doing', category: 'in_progress' },
{ id: 'testing', name: 'Testing', category: 'in_progress' },
{ id: 'finished', name: 'Finished', category: 'completed' }
];
const manager = new WorkItemManager(storage, {
statuses: customStatuses
});Custom Work Types
const customWorkTypes = [
{ id: 'story', name: 'User Story', icon: '📖' },
{ id: 'spike', name: 'Spike', icon: '🔬' },
{ id: 'epic', name: 'Epic', icon: '🎯' }
];
const manager = new WorkItemManager(storage, {
workTypes: customWorkTypes
});Integration Status
- Logger: not-applicable - Core package with no logging requirements
- Docs-Suite: ready - Complete TypeDoc API documentation
- NeverHub: not-applicable - Core package with no service discovery needs
TypeScript Support
This package is written in TypeScript with strict mode enabled and includes complete type definitions.
import type {
WorkItem,
CreateWorkItemInput,
UpdateWorkItemInput,
WorkItemFilters,
WorkItemResult,
ValidationResult,
ReadinessResult,
WorkItemStatistics
} from '@bernierllc/work-item-core';Algorithm Details
This package implements sophisticated graph algorithms for dependency management:
Circular Dependency Detection (DFS)
Uses Depth-First Search (DFS) to detect circular dependencies:
- Maintains visited set and stack for path tracking
- Detects cycles when revisiting a node in current path
- Returns all circular dependency chains found
- Time complexity: O(V + E) where V = work items, E = dependencies
Blocking Detection (BFS-style)
Uses Breadth-First Search (BFS) traversal for blocking analysis:
- Identifies incomplete dependencies blocking work item start
- Computes readiness by checking all dependency statuses
- Returns blocking items with reasons for blocking
- Time complexity: O(V + E) for full traversal
Transitive Dependencies
Recursive algorithm for finding all transitive dependencies:
- Depth-limited to prevent infinite recursion (default max depth: 10)
- Uses visited set to prevent duplicate processing
- Returns flattened list of all direct and transitive dependencies
- Time complexity: O(V + E) with early termination on visited nodes
Testing
The package includes comprehensive tests with 90%+ coverage:
npm test # Run tests in watch mode
npm run test:run # Run tests once
npm run test:coverage # Generate coverage reportTest Coverage
- Branches: 90.13%
- Functions: 93.61%
- Lines: 91.15%
- Statements: 91.15%
Includes tests for:
- CRUD operations with validation
- Hierarchical relationships
- Dependency management and circular detection
- Status and maturity progression
- Assignment workflows
- Readiness checks
- Batch operations
- Edge cases and error conditions
License
Copyright (c) 2025 Bernier LLC
This file is licensed to the client under a limited-use license. The client may use and modify this code only within the scope of the project it was delivered for. Redistribution or use in other products or commercial offerings is not permitted without written consent from Bernier LLC.
See Also
- @bernierllc/retry-policy - Exponential backoff for retries
- @bernierllc/message-queue - Message queuing with priorities
