feat: improve codex app controls and recovery
This commit is contained in:
79
server.js
79
server.js
@@ -2015,6 +2015,69 @@ function getRuntimeSessionId(session) {
|
||||
return session.claudeSessionId || null;
|
||||
}
|
||||
|
||||
async function handleReloadMcpApi(req, res, rawSessionId) {
|
||||
const token = extractBearerToken(req);
|
||||
if (!token || !activeTokens.has(token)) {
|
||||
return jsonResponse(res, 401, { ok: false, message: 'Not authenticated' });
|
||||
}
|
||||
|
||||
const sessionId = sanitizeId(rawSessionId || '');
|
||||
if (!sessionId) {
|
||||
return jsonResponse(res, 400, { ok: false, code: 'missing_session_id', message: '缺少会话 ID' });
|
||||
}
|
||||
|
||||
const session = loadSession(sessionId);
|
||||
if (!session) {
|
||||
return jsonResponse(res, 404, { ok: false, code: 'session_not_found', message: '会话不存在' });
|
||||
}
|
||||
|
||||
if (!isCodexAppSession(session)) {
|
||||
return jsonResponse(res, 400, {
|
||||
ok: false,
|
||||
code: 'reload_mcp_unsupported_agent',
|
||||
message: '重载 MCP 仅支持 Codex App 会话。旧 Codex 会话请重启本地 Codex 后再继续。',
|
||||
});
|
||||
}
|
||||
|
||||
try {
|
||||
const clientResult = getCodexAppClient();
|
||||
if (clientResult.error) {
|
||||
return jsonResponse(res, 500, {
|
||||
ok: false,
|
||||
code: 'codexapp_client_unavailable',
|
||||
message: clientResult.error,
|
||||
});
|
||||
}
|
||||
|
||||
const client = clientResult.client;
|
||||
await client.start();
|
||||
const result = typeof client.reloadMcpServers === 'function'
|
||||
? await client.reloadMcpServers()
|
||||
: await client.request('config/mcpServer/reload', {}, 30000);
|
||||
|
||||
plog('INFO', 'codex_app_mcp_reload_requested', {
|
||||
sessionId: sessionId.slice(0, 8),
|
||||
threadId: getRuntimeSessionId(session) || null,
|
||||
});
|
||||
|
||||
return jsonResponse(res, 200, {
|
||||
ok: true,
|
||||
sessionId,
|
||||
threadId: getRuntimeSessionId(session) || null,
|
||||
result: result || {},
|
||||
});
|
||||
} catch (err) {
|
||||
const unsupported = err?.code === -32601 || /not found|unknown|unsupported|method/i.test(String(err?.message || ''));
|
||||
return jsonResponse(res, unsupported ? 501 : 500, {
|
||||
ok: false,
|
||||
code: unsupported ? 'codexapp_reload_mcp_unsupported' : 'codexapp_reload_mcp_failed',
|
||||
message: unsupported
|
||||
? `当前 Codex app-server 不支持重载 MCP,请重启 Codex App。${err?.message ? `(${err.message})` : ''}`
|
||||
: `重载 MCP 失败: ${err?.message || err}`,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function setRuntimeSessionId(session, runtimeId) {
|
||||
if (!session) return;
|
||||
const agent = getSessionAgent(session);
|
||||
@@ -2900,6 +2963,11 @@ const server = http.createServer((req, res) => {
|
||||
return handleInternalMcpApi(req, res);
|
||||
}
|
||||
|
||||
const reloadMcpMatch = url.pathname.match(/^\/api\/sessions\/([^/]+)\/reload-mcp$/);
|
||||
if (req.method === 'POST' && reloadMcpMatch) {
|
||||
return handleReloadMcpApi(req, res, decodeURIComponent(reloadMcpMatch[1] || ''));
|
||||
}
|
||||
|
||||
if (req.method === 'POST' && url.pathname === '/api/attachments') {
|
||||
const token = extractBearerToken(req);
|
||||
if (!token || !activeTokens.has(token)) {
|
||||
@@ -4554,7 +4622,16 @@ function handleCodexAppUserInputResponse(ws, msg = {}) {
|
||||
|
||||
pendingCodexAppUserInputs.delete(requestId);
|
||||
clearTimeout(pending.timer);
|
||||
pending.resolve(normalizeCodexAppUserInputAnswers(msg.answers || {}));
|
||||
const action = String(msg.action || 'submit').trim();
|
||||
const isCancel = action === 'cancel';
|
||||
if (!isCancel) {
|
||||
wsSend(ws, {
|
||||
type: 'system_message',
|
||||
sessionId: pending.sessionId,
|
||||
message: '已提交 Codex App 引导输入。',
|
||||
});
|
||||
}
|
||||
pending.resolve(isCancel ? { answers: {} } : normalizeCodexAppUserInputAnswers(msg.answers || {}));
|
||||
}
|
||||
|
||||
function resolvePendingCodexAppUserInputsForSession(sessionId) {
|
||||
|
||||
Reference in New Issue
Block a user