learning_ai_clock/web/src/lib/tempo-mode.ts
2026-04-18 18:13:45 -07:00

98 lines
2.6 KiB
TypeScript

/**
* Tempo Mode engine — Phase D.3.
*
* Adjusts timer urgency and cascade presets based on the user's current
* energy/focus level. Pure TS, no React.
*/
export type TempoLevel = 'deep_focus' | 'normal' | 'low_energy' | 'winding_down';
export interface TempoConfig {
level: TempoLevel;
label: string;
description: string;
urgencyOverride: string;
cascadeOverride: string;
notificationMute: boolean;
}
export const TEMPO_CONFIGS: Record<TempoLevel, TempoConfig> = {
deep_focus: {
level: 'deep_focus',
label: 'Deep Focus',
description: 'Minimal interruptions. Only critical timers fire.',
urgencyOverride: 'passive',
cascadeOverride: 'minimal',
notificationMute: true,
},
normal: {
level: 'normal',
label: 'Normal',
description: 'Standard timer behavior.',
urgencyOverride: 'standard',
cascadeOverride: 'standard',
notificationMute: false,
},
low_energy: {
level: 'low_energy',
label: 'Low Energy',
description: 'Gentler reminders. Extended snooze times.',
urgencyOverride: 'gentle',
cascadeOverride: 'minimal',
notificationMute: false,
},
winding_down: {
level: 'winding_down',
label: 'Winding Down',
description: 'Quiet mode. Non-critical timers deferred.',
urgencyOverride: 'passive',
cascadeOverride: 'minimal',
notificationMute: true,
},
};
/**
* Compute effective urgency based on tempo mode.
*/
export function getEffectiveUrgency(
timerUrgency: string,
tempoLevel: TempoLevel,
): string {
if (tempoLevel === 'normal') return timerUrgency;
// Critical timers always fire regardless of tempo
if (timerUrgency === 'critical') return 'critical';
// In deep_focus or winding_down, downgrade non-critical to passive
if (tempoLevel === 'deep_focus' || tempoLevel === 'winding_down') {
return timerUrgency === 'important' ? 'standard' : 'passive';
}
// low_energy: make everything gentler
if (tempoLevel === 'low_energy') {
if (timerUrgency === 'important') return 'standard';
if (timerUrgency === 'standard') return 'gentle';
return 'passive';
}
return timerUrgency;
}
/**
* Compute effective cascade preset based on tempo mode.
*/
export function getEffectiveCascade(
cascadePreset: string,
tempoLevel: TempoLevel,
): string {
if (tempoLevel === 'normal') return cascadePreset;
return TEMPO_CONFIGS[tempoLevel].cascadeOverride;
}
/**
* Check if notifications should be muted for this tempo level.
*/
export function shouldMuteNotifications(tempoLevel: TempoLevel): boolean {
return TEMPO_CONFIGS[tempoLevel].notificationMute;
}