mirror of
https://github.com/siteboon/claudecodeui.git
synced 2026-07-12 01:35:45 +08:00
feat: show session name in notification and don't reload tab on clicking
--- the notification
This commit is contained in:
16
public/sw.js
16
public/sw.js
@@ -68,7 +68,7 @@ self.addEventListener('push', event => {
|
|||||||
icon: '/logo-256.png',
|
icon: '/logo-256.png',
|
||||||
badge: '/logo-128.png',
|
badge: '/logo-128.png',
|
||||||
data: payload.data || {},
|
data: payload.data || {},
|
||||||
tag: payload.data?.code || 'default',
|
tag: payload.data?.tag || `${payload.data?.sessionId || 'global'}:${payload.data?.code || 'default'}`,
|
||||||
renotify: true
|
renotify: true
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -82,16 +82,20 @@ self.addEventListener('notificationclick', event => {
|
|||||||
event.notification.close();
|
event.notification.close();
|
||||||
|
|
||||||
const sessionId = event.notification.data?.sessionId;
|
const sessionId = event.notification.data?.sessionId;
|
||||||
|
const provider = event.notification.data?.provider || null;
|
||||||
const urlPath = sessionId ? `/session/${sessionId}` : '/';
|
const urlPath = sessionId ? `/session/${sessionId}` : '/';
|
||||||
|
|
||||||
event.waitUntil(
|
event.waitUntil(
|
||||||
self.clients.matchAll({ type: 'window', includeUncontrolled: true }).then(clientList => {
|
self.clients.matchAll({ type: 'window', includeUncontrolled: true }).then(async clientList => {
|
||||||
for (const client of clientList) {
|
for (const client of clientList) {
|
||||||
if (client.url.includes(self.location.origin)) {
|
if (client.url.includes(self.location.origin)) {
|
||||||
client.focus();
|
await client.focus();
|
||||||
if (sessionId) {
|
client.postMessage({
|
||||||
client.navigate(self.location.origin + urlPath);
|
type: 'notification:navigate',
|
||||||
}
|
sessionId: sessionId || null,
|
||||||
|
provider,
|
||||||
|
urlPath
|
||||||
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -467,7 +467,7 @@ async function loadMcpConfig(cwd) {
|
|||||||
* @returns {Promise<void>}
|
* @returns {Promise<void>}
|
||||||
*/
|
*/
|
||||||
async function queryClaudeSDK(command, options = {}, ws) {
|
async function queryClaudeSDK(command, options = {}, ws) {
|
||||||
const { sessionId } = options;
|
const { sessionId, sessionSummary } = options;
|
||||||
let capturedSessionId = sessionId;
|
let capturedSessionId = sessionId;
|
||||||
let sessionCreatedSent = false;
|
let sessionCreatedSent = false;
|
||||||
let tempImagePaths = [];
|
let tempImagePaths = [];
|
||||||
@@ -507,7 +507,7 @@ async function queryClaudeSDK(command, options = {}, ws) {
|
|||||||
sessionId: capturedSessionId || sessionId || null,
|
sessionId: capturedSessionId || sessionId || null,
|
||||||
kind: 'action_required',
|
kind: 'action_required',
|
||||||
code: 'agent.notification',
|
code: 'agent.notification',
|
||||||
meta: { message },
|
meta: { message, sessionName: sessionSummary },
|
||||||
severity: 'warning',
|
severity: 'warning',
|
||||||
requiresUserAction: true,
|
requiresUserAction: true,
|
||||||
dedupeKey: `claude:hook:notification:${capturedSessionId || sessionId || 'none'}:${message}`
|
dedupeKey: `claude:hook:notification:${capturedSessionId || sessionId || 'none'}:${message}`
|
||||||
@@ -553,7 +553,7 @@ async function queryClaudeSDK(command, options = {}, ws) {
|
|||||||
sessionId: capturedSessionId || sessionId || null,
|
sessionId: capturedSessionId || sessionId || null,
|
||||||
kind: 'action_required',
|
kind: 'action_required',
|
||||||
code: 'permission.required',
|
code: 'permission.required',
|
||||||
meta: { toolName },
|
meta: { toolName, sessionName: sessionSummary },
|
||||||
severity: 'warning',
|
severity: 'warning',
|
||||||
requiresUserAction: true,
|
requiresUserAction: true,
|
||||||
dedupeKey: `claude:permission:${capturedSessionId || sessionId || 'none'}:${requestId}`
|
dedupeKey: `claude:permission:${capturedSessionId || sessionId || 'none'}:${requestId}`
|
||||||
@@ -707,6 +707,7 @@ async function queryClaudeSDK(command, options = {}, ws) {
|
|||||||
userId: ws?.userId || null,
|
userId: ws?.userId || null,
|
||||||
provider: 'claude',
|
provider: 'claude',
|
||||||
sessionId: capturedSessionId || sessionId || null,
|
sessionId: capturedSessionId || sessionId || null,
|
||||||
|
sessionName: sessionSummary,
|
||||||
stopReason: 'completed'
|
stopReason: 'completed'
|
||||||
});
|
});
|
||||||
console.log('claude-complete event sent');
|
console.log('claude-complete event sent');
|
||||||
@@ -732,6 +733,7 @@ async function queryClaudeSDK(command, options = {}, ws) {
|
|||||||
userId: ws?.userId || null,
|
userId: ws?.userId || null,
|
||||||
provider: 'claude',
|
provider: 'claude',
|
||||||
sessionId: capturedSessionId || sessionId || null,
|
sessionId: capturedSessionId || sessionId || null,
|
||||||
|
sessionName: sessionSummary,
|
||||||
error
|
error
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ function isWorkspaceTrustPrompt(text = '') {
|
|||||||
|
|
||||||
async function spawnCursor(command, options = {}, ws) {
|
async function spawnCursor(command, options = {}, ws) {
|
||||||
return new Promise(async (resolve, reject) => {
|
return new Promise(async (resolve, reject) => {
|
||||||
const { sessionId, projectPath, cwd, resume, toolsSettings, skipPermissions, model } = options;
|
const { sessionId, projectPath, cwd, resume, toolsSettings, skipPermissions, model, sessionSummary } = options;
|
||||||
let capturedSessionId = sessionId; // Track session ID throughout the process
|
let capturedSessionId = sessionId; // Track session ID throughout the process
|
||||||
let sessionCreatedSent = false; // Track if we've already sent session-created event
|
let sessionCreatedSent = false; // Track if we've already sent session-created event
|
||||||
let hasRetriedWithTrust = false;
|
let hasRetriedWithTrust = false;
|
||||||
@@ -97,6 +97,7 @@ async function spawnCursor(command, options = {}, ws) {
|
|||||||
userId: ws?.userId || null,
|
userId: ws?.userId || null,
|
||||||
provider: 'cursor',
|
provider: 'cursor',
|
||||||
sessionId: finalSessionId,
|
sessionId: finalSessionId,
|
||||||
|
sessionName: sessionSummary,
|
||||||
stopReason: 'completed'
|
stopReason: 'completed'
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
@@ -106,6 +107,7 @@ async function spawnCursor(command, options = {}, ws) {
|
|||||||
userId: ws?.userId || null,
|
userId: ws?.userId || null,
|
||||||
provider: 'cursor',
|
provider: 'cursor',
|
||||||
sessionId: finalSessionId,
|
sessionId: finalSessionId,
|
||||||
|
sessionName: sessionSummary,
|
||||||
error: error || `Cursor CLI exited with code ${code}`
|
error: error || `Cursor CLI exited with code ${code}`
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ import { notifyRunFailed, notifyRunStopped } from './services/notification-orche
|
|||||||
let activeGeminiProcesses = new Map(); // Track active processes by session ID
|
let activeGeminiProcesses = new Map(); // Track active processes by session ID
|
||||||
|
|
||||||
async function spawnGemini(command, options = {}, ws) {
|
async function spawnGemini(command, options = {}, ws) {
|
||||||
const { sessionId, projectPath, cwd, resume, toolsSettings, permissionMode, images } = options;
|
const { sessionId, projectPath, cwd, resume, toolsSettings, permissionMode, images, sessionSummary } = options;
|
||||||
let capturedSessionId = sessionId; // Track session ID throughout the process
|
let capturedSessionId = sessionId; // Track session ID throughout the process
|
||||||
let sessionCreatedSent = false; // Track if we've already sent session-created event
|
let sessionCreatedSent = false; // Track if we've already sent session-created event
|
||||||
let assistantBlocks = []; // Accumulate the full response blocks including tools
|
let assistantBlocks = []; // Accumulate the full response blocks including tools
|
||||||
@@ -189,6 +189,7 @@ async function spawnGemini(command, options = {}, ws) {
|
|||||||
userId: ws?.userId || null,
|
userId: ws?.userId || null,
|
||||||
provider: 'gemini',
|
provider: 'gemini',
|
||||||
sessionId: finalSessionId,
|
sessionId: finalSessionId,
|
||||||
|
sessionName: sessionSummary,
|
||||||
stopReason: 'completed'
|
stopReason: 'completed'
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
@@ -198,6 +199,7 @@ async function spawnGemini(command, options = {}, ws) {
|
|||||||
userId: ws?.userId || null,
|
userId: ws?.userId || null,
|
||||||
provider: 'gemini',
|
provider: 'gemini',
|
||||||
sessionId: finalSessionId,
|
sessionId: finalSessionId,
|
||||||
|
sessionName: sessionSummary,
|
||||||
error: error || terminalFailureReason || `Gemini CLI exited with code ${code}`
|
error: error || terminalFailureReason || `Gemini CLI exited with code ${code}`
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -192,6 +192,7 @@ function mapPermissionModeToCodexOptions(permissionMode) {
|
|||||||
export async function queryCodex(command, options = {}, ws) {
|
export async function queryCodex(command, options = {}, ws) {
|
||||||
const {
|
const {
|
||||||
sessionId,
|
sessionId,
|
||||||
|
sessionSummary,
|
||||||
cwd,
|
cwd,
|
||||||
projectPath,
|
projectPath,
|
||||||
model,
|
model,
|
||||||
@@ -276,6 +277,7 @@ export async function queryCodex(command, options = {}, ws) {
|
|||||||
userId: ws?.userId || null,
|
userId: ws?.userId || null,
|
||||||
provider: 'codex',
|
provider: 'codex',
|
||||||
sessionId: currentSessionId,
|
sessionId: currentSessionId,
|
||||||
|
sessionName: sessionSummary,
|
||||||
error: terminalFailure
|
error: terminalFailure
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -306,6 +308,7 @@ export async function queryCodex(command, options = {}, ws) {
|
|||||||
userId: ws?.userId || null,
|
userId: ws?.userId || null,
|
||||||
provider: 'codex',
|
provider: 'codex',
|
||||||
sessionId: currentSessionId,
|
sessionId: currentSessionId,
|
||||||
|
sessionName: sessionSummary,
|
||||||
stopReason: 'completed'
|
stopReason: 'completed'
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -330,6 +333,7 @@ export async function queryCodex(command, options = {}, ws) {
|
|||||||
userId: ws?.userId || null,
|
userId: ws?.userId || null,
|
||||||
provider: 'codex',
|
provider: 'codex',
|
||||||
sessionId: currentSessionId,
|
sessionId: currentSessionId,
|
||||||
|
sessionName: sessionSummary,
|
||||||
error
|
error
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import webPush from 'web-push';
|
import webPush from 'web-push';
|
||||||
import { notificationPreferencesDb, pushSubscriptionsDb } from '../database/db.js';
|
import { notificationPreferencesDb, pushSubscriptionsDb, sessionNamesDb } from '../database/db.js';
|
||||||
|
|
||||||
const KIND_TO_PREF_KEY = {
|
const KIND_TO_PREF_KEY = {
|
||||||
action_required: 'actionRequired',
|
action_required: 'actionRequired',
|
||||||
@@ -7,6 +7,14 @@ const KIND_TO_PREF_KEY = {
|
|||||||
error: 'error'
|
error: 'error'
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const PROVIDER_LABELS = {
|
||||||
|
claude: 'Claude',
|
||||||
|
cursor: 'Cursor',
|
||||||
|
codex: 'Codex',
|
||||||
|
gemini: 'Gemini',
|
||||||
|
system: 'System'
|
||||||
|
};
|
||||||
|
|
||||||
const recentEventKeys = new Map();
|
const recentEventKeys = new Map();
|
||||||
const DEDUPE_WINDOW_MS = 20000;
|
const DEDUPE_WINDOW_MS = 20000;
|
||||||
|
|
||||||
@@ -76,6 +84,32 @@ function normalizeErrorMessage(error) {
|
|||||||
return String(error);
|
return String(error);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function normalizeSessionName(sessionName) {
|
||||||
|
if (typeof sessionName !== 'string') {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const normalized = sessionName.replace(/\s+/g, ' ').trim();
|
||||||
|
if (!normalized) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return normalized.length > 80 ? `${normalized.slice(0, 77)}...` : normalized;
|
||||||
|
}
|
||||||
|
|
||||||
|
function resolveSessionName(event) {
|
||||||
|
const explicitSessionName = normalizeSessionName(event.meta?.sessionName);
|
||||||
|
if (explicitSessionName) {
|
||||||
|
return explicitSessionName;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!event.sessionId || !event.provider) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return normalizeSessionName(sessionNamesDb.getName(event.sessionId, event.provider));
|
||||||
|
}
|
||||||
|
|
||||||
function buildPushBody(event) {
|
function buildPushBody(event) {
|
||||||
const CODE_MAP = {
|
const CODE_MAP = {
|
||||||
'permission.required': event.meta?.toolName
|
'permission.required': event.meta?.toolName
|
||||||
@@ -86,13 +120,19 @@ function buildPushBody(event) {
|
|||||||
'agent.notification': event.meta?.message ? String(event.meta.message) : 'You have a new notification',
|
'agent.notification': event.meta?.message ? String(event.meta.message) : 'You have a new notification',
|
||||||
'push.enabled': 'Push notifications are now enabled!'
|
'push.enabled': 'Push notifications are now enabled!'
|
||||||
};
|
};
|
||||||
|
const providerLabel = PROVIDER_LABELS[event.provider] || 'Assistant';
|
||||||
|
const sessionName = resolveSessionName(event);
|
||||||
|
const message = CODE_MAP[event.code] || 'You have a new notification';
|
||||||
|
|
||||||
return {
|
return {
|
||||||
title: 'Claude Code UI',
|
title: sessionName || 'Claude Code UI',
|
||||||
body: CODE_MAP[event.code] || 'You have a new notification',
|
body: `${providerLabel}: ${message}`,
|
||||||
data: {
|
data: {
|
||||||
sessionId: event.sessionId || null,
|
sessionId: event.sessionId || null,
|
||||||
code: event.code
|
code: event.code,
|
||||||
|
provider: event.provider || null,
|
||||||
|
sessionName,
|
||||||
|
tag: `${event.provider || 'assistant'}:${event.sessionId || 'none'}:${event.code}`
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -147,7 +187,7 @@ function notifyUserIfEnabled({ userId, event }) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function notifyRunStopped({ userId, provider, sessionId = null, stopReason = 'completed' }) {
|
function notifyRunStopped({ userId, provider, sessionId = null, stopReason = 'completed', sessionName = null }) {
|
||||||
notifyUserIfEnabled({
|
notifyUserIfEnabled({
|
||||||
userId,
|
userId,
|
||||||
event: createNotificationEvent({
|
event: createNotificationEvent({
|
||||||
@@ -155,14 +195,14 @@ function notifyRunStopped({ userId, provider, sessionId = null, stopReason = 'co
|
|||||||
sessionId,
|
sessionId,
|
||||||
kind: 'stop',
|
kind: 'stop',
|
||||||
code: 'run.stopped',
|
code: 'run.stopped',
|
||||||
meta: { stopReason },
|
meta: { stopReason, sessionName },
|
||||||
severity: 'info',
|
severity: 'info',
|
||||||
dedupeKey: `${provider}:run:stop:${sessionId || 'none'}:${stopReason}`
|
dedupeKey: `${provider}:run:stop:${sessionId || 'none'}:${stopReason}`
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function notifyRunFailed({ userId, provider, sessionId = null, error }) {
|
function notifyRunFailed({ userId, provider, sessionId = null, error, sessionName = null }) {
|
||||||
const errorMessage = normalizeErrorMessage(error);
|
const errorMessage = normalizeErrorMessage(error);
|
||||||
|
|
||||||
notifyUserIfEnabled({
|
notifyUserIfEnabled({
|
||||||
@@ -172,7 +212,7 @@ function notifyRunFailed({ userId, provider, sessionId = null, error }) {
|
|||||||
sessionId,
|
sessionId,
|
||||||
kind: 'error',
|
kind: 'error',
|
||||||
code: 'run.failed',
|
code: 'run.failed',
|
||||||
meta: { error: errorMessage },
|
meta: { error: errorMessage, sessionName },
|
||||||
severity: 'error',
|
severity: 'error',
|
||||||
dedupeKey: `${provider}:run:error:${sessionId || 'none'}:${errorMessage}`
|
dedupeKey: `${provider}:run:error:${sessionId || 'none'}:${errorMessage}`
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -72,6 +72,40 @@ export default function AppContent() {
|
|||||||
};
|
};
|
||||||
}, [openSettings]);
|
}, [openSettings]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (typeof navigator === 'undefined' || !('serviceWorker' in navigator)) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleServiceWorkerMessage = (event: MessageEvent) => {
|
||||||
|
const message = event.data;
|
||||||
|
if (!message || message.type !== 'notification:navigate') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof message.provider === 'string' && message.provider.trim()) {
|
||||||
|
localStorage.setItem('selected-provider', message.provider);
|
||||||
|
}
|
||||||
|
|
||||||
|
setActiveTab('chat');
|
||||||
|
setSidebarOpen(false);
|
||||||
|
void refreshProjectsSilently();
|
||||||
|
|
||||||
|
if (typeof message.sessionId === 'string' && message.sessionId) {
|
||||||
|
navigate(`/session/${message.sessionId}`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
navigate('/');
|
||||||
|
};
|
||||||
|
|
||||||
|
navigator.serviceWorker.addEventListener('message', handleServiceWorkerMessage);
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
navigator.serviceWorker.removeEventListener('message', handleServiceWorkerMessage);
|
||||||
|
};
|
||||||
|
}, [navigate, refreshProjectsSilently, setActiveTab, setSidebarOpen]);
|
||||||
|
|
||||||
// Permission recovery: query pending permissions on WebSocket reconnect or session change
|
// Permission recovery: query pending permissions on WebSocket reconnect or session change
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const isReconnect = isConnected && !wasConnectedRef.current;
|
const isReconnect = isConnected && !wasConnectedRef.current;
|
||||||
|
|||||||
@@ -82,6 +82,24 @@ const createFakeSubmitEvent = () => {
|
|||||||
const isTemporarySessionId = (sessionId: string | null | undefined) =>
|
const isTemporarySessionId = (sessionId: string | null | undefined) =>
|
||||||
Boolean(sessionId && sessionId.startsWith('new-session-'));
|
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({
|
export function useChatComposerState({
|
||||||
selectedProject,
|
selectedProject,
|
||||||
selectedSession,
|
selectedSession,
|
||||||
@@ -603,6 +621,7 @@ export function useChatComposerState({
|
|||||||
|
|
||||||
const toolsSettings = getToolsSettings();
|
const toolsSettings = getToolsSettings();
|
||||||
const resolvedProjectPath = selectedProject.fullPath || selectedProject.path || '';
|
const resolvedProjectPath = selectedProject.fullPath || selectedProject.path || '';
|
||||||
|
const sessionSummary = getNotificationSessionSummary(selectedSession, currentInput);
|
||||||
|
|
||||||
if (provider === 'cursor') {
|
if (provider === 'cursor') {
|
||||||
sendMessage({
|
sendMessage({
|
||||||
@@ -616,6 +635,7 @@ export function useChatComposerState({
|
|||||||
resume: Boolean(effectiveSessionId),
|
resume: Boolean(effectiveSessionId),
|
||||||
model: cursorModel,
|
model: cursorModel,
|
||||||
skipPermissions: toolsSettings?.skipPermissions || false,
|
skipPermissions: toolsSettings?.skipPermissions || false,
|
||||||
|
sessionSummary,
|
||||||
toolsSettings,
|
toolsSettings,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
@@ -630,6 +650,7 @@ export function useChatComposerState({
|
|||||||
sessionId: effectiveSessionId,
|
sessionId: effectiveSessionId,
|
||||||
resume: Boolean(effectiveSessionId),
|
resume: Boolean(effectiveSessionId),
|
||||||
model: codexModel,
|
model: codexModel,
|
||||||
|
sessionSummary,
|
||||||
permissionMode: permissionMode === 'plan' ? 'default' : permissionMode,
|
permissionMode: permissionMode === 'plan' ? 'default' : permissionMode,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
@@ -644,6 +665,7 @@ export function useChatComposerState({
|
|||||||
sessionId: effectiveSessionId,
|
sessionId: effectiveSessionId,
|
||||||
resume: Boolean(effectiveSessionId),
|
resume: Boolean(effectiveSessionId),
|
||||||
model: geminiModel,
|
model: geminiModel,
|
||||||
|
sessionSummary,
|
||||||
permissionMode,
|
permissionMode,
|
||||||
toolsSettings,
|
toolsSettings,
|
||||||
},
|
},
|
||||||
@@ -660,6 +682,7 @@ export function useChatComposerState({
|
|||||||
toolsSettings,
|
toolsSettings,
|
||||||
permissionMode,
|
permissionMode,
|
||||||
model: claudeModel,
|
model: claudeModel,
|
||||||
|
sessionSummary,
|
||||||
images: uploadedImages,
|
images: uploadedImages,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
@@ -681,6 +704,7 @@ export function useChatComposerState({
|
|||||||
safeLocalStorage.removeItem(`draft_input_${selectedProject.name}`);
|
safeLocalStorage.removeItem(`draft_input_${selectedProject.name}`);
|
||||||
},
|
},
|
||||||
[
|
[
|
||||||
|
selectedSession,
|
||||||
attachedImages,
|
attachedImages,
|
||||||
claudeModel,
|
claudeModel,
|
||||||
codexModel,
|
codexModel,
|
||||||
@@ -697,7 +721,6 @@ export function useChatComposerState({
|
|||||||
resetCommandMenuState,
|
resetCommandMenuState,
|
||||||
scrollToBottom,
|
scrollToBottom,
|
||||||
selectedProject,
|
selectedProject,
|
||||||
selectedSession?.id,
|
|
||||||
sendMessage,
|
sendMessage,
|
||||||
setCanAbortSession,
|
setCanAbortSession,
|
||||||
setChatMessages,
|
setChatMessages,
|
||||||
|
|||||||
Reference in New Issue
Block a user