chore: rebuild CentOS 7 release package

This commit is contained in:
shiyue
2026-08-16 22:20:00 +08:00
parent 93641df1ad
commit 6ed8c7d30b
21 changed files with 2137 additions and 45 deletions

View File

@@ -541,7 +541,13 @@ function assertFrontendSidebarCollapseContract() {
});
assert(source.includes("const SIDEBAR_COLLAPSE_STORAGE_KEY = 'cc-web-sidebar-collapsed'"), 'Desktop sidebar preference should use a stable storage key');
assert(source.includes("const SIDEBAR_DRAWER_MEDIA_QUERY = '(max-width: 768px)'"), 'Sidebar drawer mode should match the mobile CSS breakpoint');
assert(source.includes("const SIDEBAR_DESKTOP_COLLAPSE_MEDIA_QUERY = '(width > 768px) and (hover: hover) and (pointer: fine)'"), 'Desktop collapse mode should match the hover rail CSS capabilities');
assert(source.includes("const SIDEBAR_DESKTOP_COLLAPSE_MEDIA_QUERY = '(width > 768px)'"), 'Wide sidebar collapse mode should be available by viewport width');
assert(source.includes("const SIDEBAR_HOVER_PREVIEW_MEDIA_QUERY = '(width > 768px) and (hover: hover) and (pointer: fine)'"), 'Hover preview should retain the fine-pointer capability gate');
assert(
source.includes('const sidebarDesktopCollapseMedia = window.matchMedia(SIDEBAR_DESKTOP_COLLAPSE_MEDIA_QUERY)')
&& source.includes('const sidebarHoverPreviewMedia = window.matchMedia(SIDEBAR_HOVER_PREVIEW_MEDIA_QUERY)'),
'Wide fixed collapse and hover preview should use separate media queries'
);
assert(source.includes("app.classList.toggle('sidebar-collapsed', nextCollapsed)"), 'Desktop sidebar should keep its fixed state on the app root');
assert(
indexSource.includes('id="user-outline-panel" class="user-outline-panel"')
@@ -566,19 +572,35 @@ function assertFrontendSidebarCollapseContract() {
'Sidebar toggle should preserve the mobile drawer path before using desktop fixed collapse'
);
assert(
source.includes('[sidebarDrawerMedia, sidebarDesktopCollapseMedia].forEach((media) =>')
source.includes('[sidebarDrawerMedia, sidebarDesktopCollapseMedia, sidebarHoverPreviewMedia].forEach((media) =>')
&& source.includes("media.addEventListener('change', handleSidebarInputModeChange)"),
'Sidebar should reset transient state when either drawer or desktop collapse mode changes'
);
assert(styleSource.includes('--sidebar-rail-width: 14px'), 'Collapsed desktop sidebar should retain a narrow hover rail');
const desktopCollapseStyleStart = styleSource.indexOf('@media (width > 768px) and (hover: hover) and (pointer: fine)');
const desktopCollapseStyleEnd = styleSource.indexOf('@media (prefers-reduced-motion: reduce)', desktopCollapseStyleStart);
const desktopCollapseStyleStart = styleSource.indexOf('@media (width > 768px)');
const hoverPreviewStyleStart = styleSource.indexOf('@media (width > 768px) and (hover: hover) and (pointer: fine)');
const desktopCollapseStyleEnd = hoverPreviewStyleStart;
assert(
desktopCollapseStyleStart >= 0 && desktopCollapseStyleEnd > desktopCollapseStyleStart,
'Desktop hover behavior should stay isolated from touch and narrow-screen drawers'
desktopCollapseStyleStart >= 0
&& hoverPreviewStyleStart > desktopCollapseStyleStart
&& desktopCollapseStyleEnd > desktopCollapseStyleStart,
'Wide fixed collapse styles should be separate from hover preview styles'
);
const desktopCollapseStyle = styleSource.slice(desktopCollapseStyleStart, desktopCollapseStyleEnd);
assert(
/\.menu-btn\s*\{[^}]*display:\s*inline-flex;/.test(desktopCollapseStyle),
'Wide touch viewports should keep the sidebar toggle visible'
);
assert(
!/\.app\.sidebar-collapsed \.sidebar:is\(:hover, :focus-within\)/.test(desktopCollapseStyle),
'Wide fixed collapse should not enable hover preview on touch viewports'
);
const hoverPreviewStyle = styleSource.slice(hoverPreviewStyleStart, styleSource.indexOf('@media (prefers-reduced-motion: reduce)', hoverPreviewStyleStart));
assert(
/\.app\.sidebar-collapsed \.sidebar:is\(:hover, :focus-within\)/.test(hoverPreviewStyle),
'Hover-capable desktops should retain temporary sidebar preview'
);
assert(
styleSource.includes('margin-right: calc(var(--sidebar-rail-width) - var(--sidebar-width))')
&& styleSource.includes('transform: translateX(calc(var(--sidebar-rail-width) - var(--sidebar-width)))'),
@@ -641,7 +663,7 @@ function assertFrontendSidebarCollapseContract() {
assert(
source.includes('if (isSidebarDesktopCollapseMode())')
&& source.includes("const expanded = isDrawer\n ? sidebar.classList.contains('open')\n : (isDesktopCollapsible ? !app.classList.contains('sidebar-collapsed') : true)"),
'Unsupported wide-screen pointer modes should stay visually and accessibly expanded'
'Wide touch viewports should use the fixed collapse state for labels and aria-expanded'
);
assert(
styleSource.includes("html[data-theme='gilded'] .app.sidebar-collapsed .sidebar::after")
@@ -895,7 +917,8 @@ function assertComposerSlashRoutingContract() {
assert(source.includes('if (!msg.preserveComposerDraft) return false;'), 'Frontend should restore slash drafts only for explicit failure responses');
assert(source.includes("if (msgInput.value !== '' || pendingAttachments.length > 0) return false;"), 'Frontend should not overwrite user input typed after a slash request');
assert(source.includes('rememberPendingSlashDraft(requestId, text, currentSessionId, currentAgent);'), 'Frontend should remember slash draft before clearing the composer');
assert(source.includes("send({ type: 'message', text, sessionId: currentSessionId, mode: currentMode, agent: currentAgent, requestId });"), 'Frontend slash sends should carry requestId');
assert(source.includes("const clientMessageId = isGoalSetCommandText(text) ? createLocalId('user') : '';"), 'Frontend should allocate a stable user-message id for setting /goal');
assert(source.includes('...(clientMessageId ? { clientMessageId } : {}),'), 'Frontend should send the Goal user-message id without changing other slash payloads');
assert((source.match(/applyPendingSlashDraftResponse\(msg\);/g) || []).length >= 2, 'Frontend should handle slash draft restoration on system_message and error');
const frontendCommandsMatch = source.match(/const\s+SLASH_COMMANDS\s*=\s*\[([\s\S]*?)\n\s*\];/);
@@ -919,6 +942,15 @@ function assertComposerSlashRoutingContract() {
});
assert(!knownSlashApi('/report/mcps?search') && !knownSlashApi('/help/topic'), 'Unknown slash paths should remain ordinary messages');
const goalSetSource = extractFunctionSource(source, 'isGoalSetCommandText');
const goalSetApi = new Function(`
${goalSetSource}
return isGoalSetCommandText;
`)();
assert(goalSetApi('/goal improve benchmark coverage'), 'Frontend should recognize setting /goal as a Goal bubble command');
assert(goalSetApi('/GOAL\nlong objective'), 'Frontend should recognize multiline and case-insensitive Goal objectives');
assert(!goalSetApi('/goal') && !goalSetApi('/goal pause') && !goalSetApi('/goal resume') && !goalSetApi('/goal clear'), 'Frontend should keep Goal control commands out of user bubbles');
const tokenSource = extractFunctionSource(source, 'findActiveComposerToken');
const tokenApi = new Function(`
let msgInput = null;
@@ -7032,17 +7064,40 @@ async function main() {
assert(codexAppRetryMismatchUsers.length === 1, 'Codex App retry mismatch should not duplicate the user message');
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' }));
const codexAppGoalRequestId = 'regression-goal-request';
const codexAppGoalMessageId = 'regression-goal-user-message';
ws.send(JSON.stringify({
type: 'message',
text: '/goal improve benchmark coverage',
sessionId: codexAppSession.sessionId,
mode: 'yolo',
agent: 'codexapp',
requestId: codexAppGoalRequestId,
clientMessageId: codexAppGoalMessageId,
}));
const codexAppGoalBubble = await nextMessage(messages, ws, (msg) => (
msg.type === 'session_message' &&
msg.sessionId === codexAppSession.sessionId &&
msg.message?.id === codexAppGoalMessageId
), 5000);
assert(codexAppGoalBubble.message.role === 'user', 'Setting /goal should render through the normal user-message role');
assert(codexAppGoalBubble.message.content === 'improve benchmark coverage', 'Goal user bubble should contain only the objective');
assert(codexAppGoalBubble.message.ccwebDisplayOnly === true, 'Goal user bubble should be display-only local history');
assert(codexAppGoalBubble.message.ccwebGoalCommand?.action === 'set', 'Goal user bubble should carry dedicated Goal metadata');
assert(codexAppGoalBubble.message.ccwebGoalCommand?.requestId === codexAppGoalRequestId, 'Goal metadata should preserve the stable request id');
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');
assert(codexAppGoalSyncing.transient === true, 'Codex App /goal syncing notice should auto-dismiss');
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 || ''));
assert(/Goal active/.test(codexAppGoalSet.message || ''), 'Codex App /goal should set an active goal');
assert(!/improve benchmark coverage/.test(codexAppGoalSet.message || ''), 'Goal success notice should not repeat the full objective');
assert(codexAppGoalSet.transient === true, 'Goal success notice should auto-dismiss');
const codexAppGoalBackgroundDelta = await nextMessage(messages, ws, (msg) => (
msg.type === 'text_delta' &&
msg.sessionId === codexAppSession.sessionId &&
@@ -7056,6 +7111,24 @@ async function main() {
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 improve benchmark coverage',
sessionId: codexAppSession.sessionId,
mode: 'yolo',
agent: 'codexapp',
requestId: codexAppGoalRequestId,
clientMessageId: codexAppGoalMessageId,
}));
const codexAppGoalDuplicate = await nextMessage(messages, ws, (msg) => (
msg.type === 'system_message' &&
msg.sessionId === codexAppSession.sessionId &&
/Goal 设置请求已处理/.test(msg.message || '')
), 5000);
assert(codexAppGoalDuplicate.transient === true, 'Duplicate Goal command ids should receive a compact transient acknowledgement');
await sleep(250);
assert(!messages.some((msg) => msg.type === 'session_message' && msg.message?.id === codexAppGoalMessageId), 'Duplicate Goal command ids should not append another user bubble');
assert(!messages.some((msg) => msg.type === 'text_delta' && /Goal background output: improve benchmark coverage/.test(msg.text || '')), 'Duplicate Goal command ids should not trigger another Goal RPC background turn');
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 || ''));
assert(/improve benchmark coverage/.test(codexAppGoalShow.message || ''), 'Codex App /goal should show the current goal');
@@ -7072,7 +7145,11 @@ async function main() {
const codexAppGoalEmpty = await nextMessage(messages, ws, (msg) => msg.type === 'system_message' && msg.sessionId === codexAppSession.sessionId && /用法: \/goal <目标描述>/.test(msg.message || ''));
assert(/\/goal <目标描述>/.test(codexAppGoalEmpty.message || ''), 'Codex App /goal should show usage when no goal exists');
const storedCodexAppAfterGoal = JSON.parse(fs.readFileSync(path.join(sessionsDir, `${codexAppSession.sessionId}.json`), 'utf8'));
assert(!storedCodexAppAfterGoal.messages.some((message) => message.role === 'user' && /^\/goal/.test(String(message.content || ''))), 'Codex App /goal slash commands should not be persisted as normal user messages');
const storedGoalMessages = storedCodexAppAfterGoal.messages.filter((message) => message.id === codexAppGoalMessageId);
assert(storedGoalMessages.length === 1, 'Codex App should persist exactly one Goal user bubble for a stable command id');
assert(storedGoalMessages[0].role === 'user' && storedGoalMessages[0].content === 'improve benchmark coverage', 'Persisted Goal bubble should restore as the objective-only user message');
assert(storedGoalMessages[0].ccwebDisplayOnly === true && storedGoalMessages[0].ccwebGoalCommand?.action === 'set', 'Persisted Goal bubble should remain marked as display-only Goal history');
assert(!storedCodexAppAfterGoal.messages.some((message) => message.role === 'user' && /^\/goal/.test(String(message.content || ''))), 'Raw /goal commands should never enter ordinary user-message history');
assert(storedCodexAppAfterGoal.messages.some((message) => (
message.role === 'assistant' &&
/Goal background output: improve benchmark coverage/.test(String(message.content || ''))