chore: rebuild CentOS7 release package

This commit is contained in:
shiyue
2026-07-02 08:32:49 +08:00
parent 75ffdb1c6f
commit d816ae28b9
4 changed files with 107 additions and 9 deletions

View File

@@ -872,7 +872,9 @@ function handleRequest(message) {
method: 'thread/goal/updated', method: 'thread/goal/updated',
params: { threadId: thread.id, goal: thread.goal }, params: { threadId: thread.id, goal: thread.goal },
}); });
send({ id, result: { goal: thread.goal } }); setTimeout(() => {
send({ id, result: { goal: thread.goal } });
}, 250);
return; return;
} }
if (method === 'thread/goal/clear') { if (method === 'thread/goal/clear') {

View File

@@ -1500,8 +1500,22 @@ async function main() {
assert(!storedCodexAppAfterRetryMismatch.messages.some((message) => message.role === 'assistant' && /codexapp retry thread mismatch prompt/.test(String(message.content || ''))), 'Codex App retry mismatch should not persist a successful assistant response on the wrong thread'); assert(!storedCodexAppAfterRetryMismatch.messages.some((message) => message.role === 'assistant' && /codexapp retry thread mismatch prompt/.test(String(message.content || ''))), 'Codex App retry mismatch should not persist a successful assistant response on the wrong thread');
ws.send(JSON.stringify({ type: 'message', text: '/goal improve benchmark coverage', sessionId: codexAppSession.sessionId, mode: 'yolo', agent: 'codexapp' })); ws.send(JSON.stringify({ type: 'message', text: '/goal improve benchmark coverage', sessionId: codexAppSession.sessionId, mode: 'yolo', agent: 'codexapp' }));
const codexAppGoalSyncing = await nextMessage(messages, ws, (msg) => msg.type === 'system_message' && msg.sessionId === codexAppSession.sessionId && /正在同步 Goal/.test(msg.message || ''), 5000);
assert(/正在同步 Goal/.test(codexAppGoalSyncing.message || ''), 'Codex App /goal should immediately show a syncing notice');
const codexAppGoalRunningList = await nextMessage(messages, ws, (msg) => (
msg.type === 'session_list' &&
Array.isArray(msg.sessions) &&
msg.sessions.some((session) => session.id === codexAppSession.sessionId && session.isRunning)
), 5000);
assert(codexAppGoalRunningList.sessions.some((session) => session.id === codexAppSession.sessionId && session.isRunning), 'Codex App /goal RPC should mark the session running while waiting for app-server');
const codexAppGoalSet = await nextMessage(messages, ws, (msg) => msg.type === 'system_message' && msg.sessionId === codexAppSession.sessionId && /Goal active/.test(msg.message || '') && /improve benchmark coverage/.test(msg.message || '')); const codexAppGoalSet = await nextMessage(messages, ws, (msg) => msg.type === 'system_message' && msg.sessionId === codexAppSession.sessionId && /Goal active/.test(msg.message || '') && /improve benchmark coverage/.test(msg.message || ''));
assert(/Goal active/.test(codexAppGoalSet.message || ''), 'Codex App /goal should set an active goal'); assert(/Goal active/.test(codexAppGoalSet.message || ''), 'Codex App /goal should set an active goal');
const codexAppGoalIdleList = await nextMessage(messages, ws, (msg) => (
msg.type === 'session_list' &&
Array.isArray(msg.sessions) &&
msg.sessions.some((session) => session.id === codexAppSession.sessionId && !session.isRunning)
), 5000);
assert(codexAppGoalIdleList.sessions.some((session) => session.id === codexAppSession.sessionId && !session.isRunning), 'Codex App /goal RPC should clear running state after app-server responds');
ws.send(JSON.stringify({ type: 'message', text: '/goal', sessionId: codexAppSession.sessionId, mode: 'yolo', agent: 'codexapp' })); ws.send(JSON.stringify({ type: 'message', text: '/goal', sessionId: codexAppSession.sessionId, mode: 'yolo', agent: 'codexapp' }));
const codexAppGoalShow = await nextMessage(messages, ws, (msg) => msg.type === 'system_message' && msg.sessionId === codexAppSession.sessionId && /Goal active/.test(msg.message || '') && /improve benchmark coverage/.test(msg.message || '')); const codexAppGoalShow = await nextMessage(messages, ws, (msg) => msg.type === 'system_message' && msg.sessionId === codexAppSession.sessionId && /Goal active/.test(msg.message || '') && /improve benchmark coverage/.test(msg.message || ''));
assert(/improve benchmark coverage/.test(codexAppGoalShow.message || ''), 'Codex App /goal should show the current goal'); assert(/improve benchmark coverage/.test(codexAppGoalShow.message || ''), 'Codex App /goal should show the current goal');

View File

@@ -662,6 +662,9 @@ const activeProcesses = new Map();
// Active Codex app-server turns: sessionId -> { ws, threadId, turnId, fullText, toolCalls } // Active Codex app-server turns: sessionId -> { ws, threadId, turnId, fullText, toolCalls }
const activeCodexAppTurns = new Map(); const activeCodexAppTurns = new Map();
// Active Codex app-server goal RPCs: sessionId -> { id, ws, action, cancelled }
const activeCodexAppGoalCommands = new Map();
// ccweb MCP child agents tracked from Codex App native collaboration mode: // ccweb MCP child agents tracked from Codex App native collaboration mode:
// childThreadId -> { parentSessionId, parentThreadId, spawnToolId, ...state } // childThreadId -> { parentSessionId, parentThreadId, spawnToolId, ...state }
const ccwebMcpChildThreads = new Map(); const ccwebMcpChildThreads = new Map();
@@ -2906,7 +2909,7 @@ function isCodexLikeSession(session) {
} }
function isSessionRunning(sessionId) { function isSessionRunning(sessionId) {
return activeProcesses.has(sessionId) || activeCodexAppTurns.has(sessionId); return activeProcesses.has(sessionId) || activeCodexAppTurns.has(sessionId) || activeCodexAppGoalCommands.has(sessionId);
} }
function getRuntimeSessionId(session) { function getRuntimeSessionId(session) {
@@ -6725,6 +6728,34 @@ function isCodexGoalUnsupportedError(err) {
|| /goals feature is disabled|unsupported remote app-server request|method not found|unknown mock method/i.test(detail); || /goals feature is disabled|unsupported remote app-server request|method not found|unknown mock method/i.test(detail);
} }
function isCurrentCodexAppGoalCommand(sessionId, entry) {
return !!entry && activeCodexAppGoalCommands.get(sessionId)?.id === entry.id && !entry.cancelled;
}
function finishCodexAppGoalCommand(sessionId, entry) {
if (!entry || activeCodexAppGoalCommands.get(sessionId)?.id !== entry.id) return false;
activeCodexAppGoalCommands.delete(sessionId);
broadcastSessionList();
return true;
}
function cancelCodexAppGoalCommand(sessionId, ws = null) {
const entry = activeCodexAppGoalCommands.get(sessionId);
if (!entry) return false;
entry.cancelled = true;
activeCodexAppGoalCommands.delete(sessionId);
const targetWs = ws || entry.ws || null;
if (targetWs) {
wsSend(targetWs, {
type: 'system_message',
sessionId,
message: '已取消 Goal 同步状态。底层 Codex app-server 请求可能仍会自然返回,结果将被忽略。',
});
}
broadcastSessionList();
return true;
}
async function handleCodexAppGoalSlashCommand(ws, text, session) { async function handleCodexAppGoalSlashCommand(ws, text, session) {
const command = parseCodexGoalCommand(text); const command = parseCodexGoalCommand(text);
if (!command) return; if (!command) return;
@@ -6741,29 +6772,49 @@ async function handleCodexAppGoalSlashCommand(ws, text, session) {
wsSend(ws, { type: 'system_message', sessionId: session.id, message: command.error }); wsSend(ws, { type: 'system_message', sessionId: session.id, message: command.error });
return; return;
} }
if (activeCodexAppGoalCommands.has(session.id)) {
wsSend(ws, { type: 'system_message', sessionId: session.id, message: 'Codex App Goal 正在同步,请稍候。' });
return;
}
const activeGoalCommand = {
id: crypto.randomUUID(),
ws,
action: command.action,
cancelled: false,
startedAt: new Date().toISOString(),
};
activeCodexAppGoalCommands.set(session.id, activeGoalCommand);
wsSend(ws, { type: 'system_message', sessionId: session.id, message: '正在同步 Goal...' });
broadcastSessionList();
try { try {
const { client, threadId } = await ensureCodexAppGoalThread(session); const { client, threadId } = await ensureCodexAppGoalThread(session);
if (!isCurrentCodexAppGoalCommand(session.id, activeGoalCommand)) return;
if (command.action === 'show') { if (command.action === 'show') {
const response = await client.request('thread/goal/get', { threadId }, 30000); const response = await client.request('thread/goal/get', { threadId }, 30000);
if (!isCurrentCodexAppGoalCommand(session.id, activeGoalCommand)) return;
const goal = normalizeCodexThreadGoal(response?.goal, threadId); const goal = normalizeCodexThreadGoal(response?.goal, threadId);
wsSend(ws, { const targetWs = activeGoalCommand.ws || ws;
wsSend(targetWs, {
type: 'system_message', type: 'system_message',
sessionId: session.id, sessionId: session.id,
message: goal ? formatCodexGoalUsage(goal) : '用法: /goal <目标描述>', message: goal ? formatCodexGoalUsage(goal) : '用法: /goal <目标描述>',
}); });
sendSessionList(ws); sendSessionList(targetWs);
return; return;
} }
if (command.action === 'clear') { if (command.action === 'clear') {
const response = await client.request('thread/goal/clear', { threadId }, 30000); const response = await client.request('thread/goal/clear', { threadId }, 30000);
wsSend(ws, { if (!isCurrentCodexAppGoalCommand(session.id, activeGoalCommand)) return;
const targetWs = activeGoalCommand.ws || ws;
wsSend(targetWs, {
type: 'system_message', type: 'system_message',
sessionId: session.id, sessionId: session.id,
message: response?.cleared ? 'Goal cleared' : 'No goal to clear', message: response?.cleared ? 'Goal cleared' : 'No goal to clear',
}); });
sendSessionList(ws); sendSessionList(targetWs);
return; return;
} }
@@ -6772,18 +6823,24 @@ async function handleCodexAppGoalSlashCommand(ws, text, session) {
...(command.action === 'set' ? { objective: command.objective } : {}), ...(command.action === 'set' ? { objective: command.objective } : {}),
status: command.action === 'pause' ? 'paused' : 'active', status: command.action === 'pause' ? 'paused' : 'active',
}, 30000); }, 30000);
if (!isCurrentCodexAppGoalCommand(session.id, activeGoalCommand)) return;
const goal = normalizeCodexThreadGoal(response?.goal, threadId); const goal = normalizeCodexThreadGoal(response?.goal, threadId);
wsSend(ws, { const targetWs = activeGoalCommand.ws || ws;
wsSend(targetWs, {
type: 'system_message', type: 'system_message',
sessionId: session.id, sessionId: session.id,
message: goal ? formatCodexGoalUsage(goal) : 'Goal updated', message: goal ? formatCodexGoalUsage(goal) : 'Goal updated',
}); });
sendSessionList(ws); sendSessionList(targetWs);
} catch (err) { } catch (err) {
const message = isCodexGoalUnsupportedError(err) const message = isCodexGoalUnsupportedError(err)
? '当前 Codex app-server 不支持 /goal请升级 Codex 或启用 goals feature。' ? '当前 Codex app-server 不支持 /goal请升级 Codex 或启用 goals feature。'
: `Goal failed: ${err?.message || err}`; : `Goal failed: ${err?.message || err}`;
wsSend(ws, { type: 'system_message', sessionId: session.id, message }); if (isCurrentCodexAppGoalCommand(session.id, activeGoalCommand)) {
wsSend(activeGoalCommand.ws || ws, { type: 'system_message', sessionId: session.id, message });
}
} finally {
finishCodexAppGoalCommand(session.id, activeGoalCommand);
} }
} }
@@ -6799,6 +6856,10 @@ function handleSlashCommand(ws, text, sessionId, fallbackAgent) {
wsSend(ws, { type: 'system_message', message: 'Codex App 运行中暂不支持 slash 指令,请等待完成或点击停止。' }); wsSend(ws, { type: 'system_message', message: 'Codex App 运行中暂不支持 slash 指令,请等待完成或点击停止。' });
return; return;
} }
if (session && isCodexAppSession(session) && activeCodexAppGoalCommands.has(sessionId)) {
wsSend(ws, { type: 'system_message', sessionId, message: 'Codex App Goal 正在同步,请稍候。' });
return;
}
switch (cmd) { switch (cmd) {
case '/clear': { case '/clear': {
@@ -7338,6 +7399,11 @@ function handleLoadSession(ws, msg) {
text: truncateTextValue(entry.fullText || '', SESSION_MESSAGE_CONTENT_MAX_CHARS), text: truncateTextValue(entry.fullText || '', SESSION_MESSAGE_CONTENT_MAX_CHARS),
toolCalls: sanitizeToolCallsForPersist(entry.toolCalls || []), toolCalls: sanitizeToolCallsForPersist(entry.toolCalls || []),
}); });
} else if (activeCodexAppGoalCommands.has(sessionId)) {
const entry = activeCodexAppGoalCommands.get(sessionId);
entry.ws = ws;
entry.wsDisconnectTime = null;
wsSend(ws, { type: 'system_message', sessionId, message: '正在同步 Goal...' });
} }
} }
@@ -7406,6 +7472,11 @@ function handleDeleteSession(ws, sessionId) {
pendingSlashCommands.delete(sessionId); pendingSlashCommands.delete(sessionId);
pendingCompactRetries.delete(sessionId); pendingCompactRetries.delete(sessionId);
cancelCodexCapacityRetry(sessionId); cancelCodexCapacityRetry(sessionId);
if (activeCodexAppGoalCommands.has(sessionId)) {
const entry = activeCodexAppGoalCommands.get(sessionId);
entry.cancelled = true;
activeCodexAppGoalCommands.delete(sessionId);
}
deleteCrossConversationRepliesForSession(sessionId); deleteCrossConversationRepliesForSession(sessionId);
for (const [threadId, child] of ccwebMcpChildThreads.entries()) { for (const [threadId, child] of ccwebMcpChildThreads.entries()) {
if (child.parentSessionId === sessionId) ccwebMcpChildThreads.delete(threadId); if (child.parentSessionId === sessionId) ccwebMcpChildThreads.delete(threadId);
@@ -7525,6 +7596,7 @@ function handleAbort(ws) {
const sessionId = wsSessionMap.get(ws); const sessionId = wsSessionMap.get(ws);
if (!sessionId) return; if (!sessionId) return;
if (handleCodexAppAbortSession(sessionId, ws)) return; if (handleCodexAppAbortSession(sessionId, ws)) return;
if (cancelCodexAppGoalCommand(sessionId, ws)) return;
const entry = activeProcesses.get(sessionId); const entry = activeProcesses.get(sessionId);
if (!entry) { if (!entry) {
if (cancelCodexCapacityRetry(sessionId)) { if (cancelCodexCapacityRetry(sessionId)) {
@@ -7642,6 +7714,10 @@ function handleMessage(ws, msg, options = {}) {
return handleCodexAppSteerMessage(ws, msg, options); return handleCodexAppSteerMessage(ws, msg, options);
} }
if (sessionId && activeCodexAppGoalCommands.has(sessionId)) {
return fail('session_running', 'Codex App Goal 正在同步,请稍候。');
}
if (sessionId && activeProcesses.has(sessionId)) { if (sessionId && activeProcesses.has(sessionId)) {
return fail('session_running', '正在处理中,请先点击停止按钮。'); return fail('session_running', '正在处理中,请先点击停止按钮。');
} }
@@ -7968,6 +8044,12 @@ function detachWsFromActiveRuntimes(ws, options = {}) {
if (disconnectTime) entry.wsDisconnectTime = disconnectTime; if (disconnectTime) entry.wsDisconnectTime = disconnectTime;
} }
} }
for (const [, entry] of activeCodexAppGoalCommands) {
if (entry.ws === ws) {
entry.ws = null;
if (disconnectTime) entry.wsDisconnectTime = disconnectTime;
}
}
} }
function findCodexAppEntryByRuntime(params = {}) { function findCodexAppEntryByRuntime(params = {}) {