fix(shell): use correct session id

This commit is contained in:
Haileyesus
2026-06-11 21:04:31 +03:00
parent 00e526b6e9
commit 89f05247ed
2 changed files with 61 additions and 33 deletions

View File

@@ -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,

View File

@@ -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`;
} }