mirror of
https://github.com/siteboon/claudecodeui.git
synced 2026-07-11 00:45:42 +08:00
fix(shell): use correct session id
This commit is contained in:
@@ -112,7 +112,17 @@ const wss = createWebSocketServer(server, {
|
|||||||
getPendingApprovalsForSession,
|
getPendingApprovalsForSession,
|
||||||
},
|
},
|
||||||
shell: {
|
shell: {
|
||||||
getSessionById: (sessionId) => sessionManager.getSession(sessionId),
|
resolveProviderSessionId: (sessionId, provider) => {
|
||||||
|
const dbSession = sessionsDb.getSessionById(sessionId);
|
||||||
|
const legacyGeminiSession =
|
||||||
|
provider === 'gemini' ? sessionManager.getSession(sessionId) : null;
|
||||||
|
|
||||||
|
if (dbSession) {
|
||||||
|
return dbSession.provider_session_id ?? legacyGeminiSession?.cliSessionId ?? null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return legacyGeminiSession?.cliSessionId;
|
||||||
|
},
|
||||||
stripAnsiSequences,
|
stripAnsiSequences,
|
||||||
normalizeDetectedUrl,
|
normalizeDetectedUrl,
|
||||||
extractUrlsFromText,
|
extractUrlsFromText,
|
||||||
|
|||||||
@@ -35,7 +35,10 @@ const PTY_SESSION_TIMEOUT = 30 * 60 * 1000;
|
|||||||
const SHELL_URL_PARSE_BUFFER_LIMIT = 32768;
|
const SHELL_URL_PARSE_BUFFER_LIMIT = 32768;
|
||||||
|
|
||||||
type ShellWebSocketDependencies = {
|
type ShellWebSocketDependencies = {
|
||||||
getSessionById: (sessionId: string) => { cliSessionId?: string } | null | undefined;
|
resolveProviderSessionId: (
|
||||||
|
sessionId: string,
|
||||||
|
provider: string,
|
||||||
|
) => string | null | undefined;
|
||||||
stripAnsiSequences: (content: string) => string;
|
stripAnsiSequences: (content: string) => string;
|
||||||
normalizeDetectedUrl: (url: string) => string | null;
|
normalizeDetectedUrl: (url: string) => string | null;
|
||||||
extractUrlsFromText: (content: string) => string[];
|
extractUrlsFromText: (content: string) => string[];
|
||||||
@@ -76,6 +79,36 @@ function parseShellMessage(rawMessage: RawData): ShellIncomingMessage | null {
|
|||||||
return payload as ShellIncomingMessage;
|
return payload as ShellIncomingMessage;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const SAFE_SESSION_ID_PATTERN = /^[a-zA-Z0-9_.\-:]+$/;
|
||||||
|
|
||||||
|
function resolveResumeSessionId(
|
||||||
|
message: ShellIncomingMessage,
|
||||||
|
dependencies: ShellWebSocketDependencies
|
||||||
|
): string {
|
||||||
|
const hasSession = readBoolean(message.hasSession);
|
||||||
|
const sessionId = readString(message.sessionId);
|
||||||
|
const provider = readString(message.provider, 'claude');
|
||||||
|
|
||||||
|
if (!hasSession || !sessionId) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
let resumeSessionId: string | null | undefined;
|
||||||
|
try {
|
||||||
|
resumeSessionId = dependencies.resolveProviderSessionId(sessionId, provider);
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Failed to resolve provider session ID:', error);
|
||||||
|
resumeSessionId = undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
const resolvedSessionId = resumeSessionId === undefined ? sessionId : resumeSessionId;
|
||||||
|
if (!resolvedSessionId || !SAFE_SESSION_ID_PATTERN.test(resolvedSessionId)) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
return resolvedSessionId;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Resolves provider command line for plain shell and agent-backed shell modes.
|
* Resolves provider command line for plain shell and agent-backed shell modes.
|
||||||
*/
|
*/
|
||||||
@@ -84,10 +117,9 @@ function buildShellCommand(
|
|||||||
dependencies: ShellWebSocketDependencies
|
dependencies: ShellWebSocketDependencies
|
||||||
): string {
|
): string {
|
||||||
const hasSession = readBoolean(message.hasSession);
|
const hasSession = readBoolean(message.hasSession);
|
||||||
const sessionId = readString(message.sessionId);
|
|
||||||
const initialCommand = readString(message.initialCommand);
|
const initialCommand = readString(message.initialCommand);
|
||||||
const provider = readString(message.provider, 'claude');
|
const provider = readString(message.provider, 'claude');
|
||||||
const safeSessionIdPattern = /^[a-zA-Z0-9_.\-:]+$/;
|
const resumeSessionId = resolveResumeSessionId(message, dependencies);
|
||||||
const isPlainShell =
|
const isPlainShell =
|
||||||
readBoolean(message.isPlainShell) ||
|
readBoolean(message.isPlainShell) ||
|
||||||
(!!initialCommand && !hasSession) ||
|
(!!initialCommand && !hasSession) ||
|
||||||
@@ -98,58 +130,43 @@ function buildShellCommand(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (provider === 'cursor') {
|
if (provider === 'cursor') {
|
||||||
if (hasSession && sessionId) {
|
if (resumeSessionId) {
|
||||||
return `cursor-agent --resume="${sessionId}"`;
|
return `cursor-agent --resume="${resumeSessionId}"`;
|
||||||
}
|
}
|
||||||
return 'cursor-agent';
|
return 'cursor-agent';
|
||||||
}
|
}
|
||||||
|
|
||||||
if (provider === 'codex') {
|
if (provider === 'codex') {
|
||||||
if (hasSession && sessionId) {
|
if (resumeSessionId) {
|
||||||
if (os.platform() === 'win32') {
|
if (os.platform() === 'win32') {
|
||||||
return `codex resume "${sessionId}"; if ($LASTEXITCODE -ne 0) { codex }`;
|
return `codex resume "${resumeSessionId}"; if ($LASTEXITCODE -ne 0) { codex }`;
|
||||||
}
|
}
|
||||||
return `codex resume "${sessionId}" || codex`;
|
return `codex resume "${resumeSessionId}" || codex`;
|
||||||
}
|
}
|
||||||
return 'codex';
|
return 'codex';
|
||||||
}
|
}
|
||||||
|
|
||||||
if (provider === 'gemini') {
|
if (provider === 'gemini') {
|
||||||
const command = initialCommand || 'gemini';
|
const command = initialCommand || 'gemini';
|
||||||
let resumeId = sessionId;
|
if (resumeSessionId) {
|
||||||
if (hasSession && sessionId) {
|
return `${command} --resume "${resumeSessionId}"`;
|
||||||
try {
|
|
||||||
const existingSession = dependencies.getSessionById(sessionId);
|
|
||||||
if (existingSession && existingSession.cliSessionId) {
|
|
||||||
resumeId = existingSession.cliSessionId;
|
|
||||||
if (!safeSessionIdPattern.test(resumeId)) {
|
|
||||||
resumeId = '';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Failed to get Gemini CLI session ID:', error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (hasSession && resumeId) {
|
|
||||||
return `${command} --resume "${resumeId}"`;
|
|
||||||
}
|
}
|
||||||
return command;
|
return command;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (provider === 'opencode') {
|
if (provider === 'opencode') {
|
||||||
if (hasSession && sessionId) {
|
if (resumeSessionId) {
|
||||||
return `opencode --session "${sessionId}"`;
|
return `opencode --session "${resumeSessionId}"`;
|
||||||
}
|
}
|
||||||
return initialCommand || 'opencode';
|
return initialCommand || 'opencode';
|
||||||
}
|
}
|
||||||
|
|
||||||
const command = initialCommand || 'claude';
|
const command = initialCommand || 'claude';
|
||||||
if (hasSession && sessionId) {
|
if (resumeSessionId) {
|
||||||
if (os.platform() === 'win32') {
|
if (os.platform() === 'win32') {
|
||||||
return `claude --resume "${sessionId}"; if ($LASTEXITCODE -ne 0) { claude }`;
|
return `claude --resume "${resumeSessionId}"; if ($LASTEXITCODE -ne 0) { claude }`;
|
||||||
}
|
}
|
||||||
return `claude --resume "${sessionId}" || claude`;
|
return `claude --resume "${resumeSessionId}" || claude`;
|
||||||
}
|
}
|
||||||
return command;
|
return command;
|
||||||
}
|
}
|
||||||
@@ -261,6 +278,7 @@ export function handleShellConnection(
|
|||||||
}
|
}
|
||||||
|
|
||||||
const shellCommand = buildShellCommand(data, dependencies);
|
const shellCommand = buildShellCommand(data, dependencies);
|
||||||
|
const resumeSessionId = resolveResumeSessionId(data, dependencies);
|
||||||
const shell = os.platform() === 'win32' ? 'powershell.exe' : 'bash';
|
const shell = os.platform() === 'win32' ? 'powershell.exe' : 'bash';
|
||||||
const shellArgs =
|
const shellArgs =
|
||||||
os.platform() === 'win32' ? ['-Command', shellCommand] : ['-c', shellCommand];
|
os.platform() === 'win32' ? ['-Command', shellCommand] : ['-c', shellCommand];
|
||||||
@@ -406,8 +424,8 @@ export function handleShellConnection(
|
|||||||
: provider === 'opencode'
|
: provider === 'opencode'
|
||||||
? 'OpenCode'
|
? 'OpenCode'
|
||||||
: 'Claude';
|
: 'Claude';
|
||||||
welcomeMsg = hasSession
|
welcomeMsg = hasSession && resumeSessionId
|
||||||
? `\x1b[36mResuming ${providerName} session ${sessionId} in: ${projectPath}\x1b[0m\r\n`
|
? `\x1b[36mResuming ${providerName} session ${resumeSessionId} in: ${projectPath}\x1b[0m\r\n`
|
||||||
: `\x1b[36mStarting new ${providerName} session in: ${projectPath}\x1b[0m\r\n`;
|
: `\x1b[36mStarting new ${providerName} session in: ${projectPath}\x1b[0m\r\n`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user