feat: Add error handling to auto-mode facade and implement followUp feature. Fix Claude weekly usage indicator. Fix mobile card drag

This commit is contained in:
gsxdsm
2026-02-16 18:58:42 -08:00
parent 2805c0ea53
commit 416ef3a394
15 changed files with 552 additions and 76 deletions

View File

@@ -151,6 +151,96 @@ describe('FeatureStateManager', () => {
expect(savedFeature.justFinishedAt).toBeUndefined();
});
it('should finalize in_progress and pending tasks when moving to waiting_approval', async () => {
const featureWithTasks: Feature = {
...mockFeature,
status: 'in_progress',
planSpec: {
status: 'approved',
version: 1,
reviewedByUser: true,
currentTaskId: 'task-2',
tasksCompleted: 1,
tasks: [
{ id: 'task-1', title: 'Task 1', status: 'completed', description: 'First task' },
{ id: 'task-2', title: 'Task 2', status: 'in_progress', description: 'Second task' },
{ id: 'task-3', title: 'Task 3', status: 'pending', description: 'Third task' },
],
},
};
(readJsonWithRecovery as Mock).mockResolvedValue({
data: featureWithTasks,
recovered: false,
source: 'main',
});
await manager.updateFeatureStatus('/project', 'feature-123', 'waiting_approval');
const savedFeature = (atomicWriteJson as Mock).mock.calls[0][1] as Feature;
// All tasks should be completed
expect(savedFeature.planSpec?.tasks?.[0].status).toBe('completed');
expect(savedFeature.planSpec?.tasks?.[1].status).toBe('completed');
expect(savedFeature.planSpec?.tasks?.[2].status).toBe('completed');
// currentTaskId should be cleared
expect(savedFeature.planSpec?.currentTaskId).toBeUndefined();
// tasksCompleted should equal total tasks
expect(savedFeature.planSpec?.tasksCompleted).toBe(3);
});
it('should finalize tasks when moving to verified status', async () => {
const featureWithTasks: Feature = {
...mockFeature,
status: 'in_progress',
planSpec: {
status: 'approved',
version: 1,
reviewedByUser: true,
currentTaskId: 'task-2',
tasksCompleted: 1,
tasks: [
{ id: 'task-1', title: 'Task 1', status: 'completed', description: 'First task' },
{ id: 'task-2', title: 'Task 2', status: 'in_progress', description: 'Second task' },
{ id: 'task-3', title: 'Task 3', status: 'pending', description: 'Third task' },
],
},
};
(readJsonWithRecovery as Mock).mockResolvedValue({
data: featureWithTasks,
recovered: false,
source: 'main',
});
await manager.updateFeatureStatus('/project', 'feature-123', 'verified');
const savedFeature = (atomicWriteJson as Mock).mock.calls[0][1] as Feature;
// All tasks should be completed
expect(savedFeature.planSpec?.tasks?.[0].status).toBe('completed');
expect(savedFeature.planSpec?.tasks?.[1].status).toBe('completed');
expect(savedFeature.planSpec?.tasks?.[2].status).toBe('completed');
// currentTaskId should be cleared
expect(savedFeature.planSpec?.currentTaskId).toBeUndefined();
// tasksCompleted should equal total tasks
expect(savedFeature.planSpec?.tasksCompleted).toBe(3);
// justFinishedAt should be cleared for verified
expect(savedFeature.justFinishedAt).toBeUndefined();
});
it('should handle waiting_approval without planSpec tasks gracefully', async () => {
(readJsonWithRecovery as Mock).mockResolvedValue({
data: { ...mockFeature },
recovered: false,
source: 'main',
});
await manager.updateFeatureStatus('/project', 'feature-123', 'waiting_approval');
const savedFeature = (atomicWriteJson as Mock).mock.calls[0][1] as Feature;
expect(savedFeature.status).toBe('waiting_approval');
expect(savedFeature.justFinishedAt).toBeDefined();
});
it('should create notification for waiting_approval status', async () => {
const mockNotificationService = { createNotification: vi.fn() };
(getNotificationService as Mock).mockReturnValue(mockNotificationService);