feat: introduce notification system and claude notifications (#450)

* feat: introduce notification system and claude notifications

* fix(sw): prevent caching of API requests and WebSocket upgrades

* default to false for webpush notifications and translations for the button

* fix: notifications orchestrator and add a notification when  first enabled

* fix: remove unused state update and dependency in settings controller hook

* fix: show notifications settings tab

* fix: add notifications for response completion for all providers

* feat: show session name in notification and don't reload tab on clicking
--- the notification

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: Haileyesus <something@gmail.com>
This commit is contained in:
Simos Mikelatos
2026-03-13 16:59:09 +01:00
committed by GitHub
parent 6f6dacad5e
commit 45e71a0e73
36 changed files with 1629 additions and 69 deletions

View File

@@ -82,6 +82,24 @@ const createFakeSubmitEvent = () => {
const isTemporarySessionId = (sessionId: string | null | undefined) =>
Boolean(sessionId && sessionId.startsWith('new-session-'));
const getNotificationSessionSummary = (
selectedSession: ProjectSession | null,
fallbackInput: string,
): string | null => {
const sessionSummary = selectedSession?.summary || selectedSession?.name || selectedSession?.title;
if (typeof sessionSummary === 'string' && sessionSummary.trim()) {
const normalized = sessionSummary.replace(/\s+/g, ' ').trim();
return normalized.length > 80 ? `${normalized.slice(0, 77)}...` : normalized;
}
const normalizedFallback = fallbackInput.replace(/\s+/g, ' ').trim();
if (!normalizedFallback) {
return null;
}
return normalizedFallback.length > 80 ? `${normalizedFallback.slice(0, 77)}...` : normalizedFallback;
};
export function useChatComposerState({
selectedProject,
selectedSession,
@@ -603,6 +621,7 @@ export function useChatComposerState({
const toolsSettings = getToolsSettings();
const resolvedProjectPath = selectedProject.fullPath || selectedProject.path || '';
const sessionSummary = getNotificationSessionSummary(selectedSession, currentInput);
if (provider === 'cursor') {
sendMessage({
@@ -616,6 +635,7 @@ export function useChatComposerState({
resume: Boolean(effectiveSessionId),
model: cursorModel,
skipPermissions: toolsSettings?.skipPermissions || false,
sessionSummary,
toolsSettings,
},
});
@@ -630,6 +650,7 @@ export function useChatComposerState({
sessionId: effectiveSessionId,
resume: Boolean(effectiveSessionId),
model: codexModel,
sessionSummary,
permissionMode: permissionMode === 'plan' ? 'default' : permissionMode,
},
});
@@ -644,6 +665,7 @@ export function useChatComposerState({
sessionId: effectiveSessionId,
resume: Boolean(effectiveSessionId),
model: geminiModel,
sessionSummary,
permissionMode,
toolsSettings,
},
@@ -660,6 +682,7 @@ export function useChatComposerState({
toolsSettings,
permissionMode,
model: claudeModel,
sessionSummary,
images: uploadedImages,
},
});
@@ -681,6 +704,7 @@ export function useChatComposerState({
safeLocalStorage.removeItem(`draft_input_${selectedProject.name}`);
},
[
selectedSession,
attachedImages,
claudeModel,
codexModel,
@@ -697,7 +721,6 @@ export function useChatComposerState({
resetCommandMenuState,
scrollToBottom,
selectedProject,
selectedSession?.id,
sendMessage,
setCanAbortSession,
setChatMessages,