feat: add MCP session visibility toggle and rebuild release
This commit is contained in:
@@ -5377,6 +5377,120 @@ function assertMultiAgentV2CompatibilityContract() {
|
||||
assert(frontendSource.includes('entry.agentPath ? `路径: ${entry.agentPath}`'), 'Sub-agent cards should expose the canonical agent path');
|
||||
}
|
||||
|
||||
function assertMcpSessionVisibilityContract() {
|
||||
const frontendSource = fs.readFileSync(PUBLIC_APP_PATH, 'utf8');
|
||||
const indexSource = fs.readFileSync(PUBLIC_INDEX_PATH, 'utf8');
|
||||
const styleSource = fs.readFileSync(PUBLIC_STYLE_PATH, 'utf8');
|
||||
|
||||
const toggleMarkup = indexSource.match(/<button\b[^>]*\bid="mcp-session-visibility-toggle"[^>]*>/)?.[0] || '';
|
||||
assert(toggleMarkup, 'MCP-created session visibility toggle should exist as a stable sidebar button');
|
||||
[
|
||||
'type="button"',
|
||||
'title=',
|
||||
'aria-label=',
|
||||
'aria-pressed="false"',
|
||||
].forEach((attribute) => {
|
||||
assert(toggleMarkup.includes(attribute), `MCP-created session visibility toggle should expose ${attribute}`);
|
||||
});
|
||||
assert(/\bclass="[^"]*\bicon-only\b[^"]*"/.test(toggleMarkup), 'MCP-created session visibility toggle should be an icon-only button');
|
||||
const searchRowIndex = indexSource.indexOf('class="session-search-row"');
|
||||
const toggleIndex = indexSource.indexOf('id="mcp-session-visibility-toggle"');
|
||||
const sessionListIndex = indexSource.indexOf('id="session-list"');
|
||||
assert(
|
||||
searchRowIndex >= 0 && toggleIndex > searchRowIndex && sessionListIndex > toggleIndex,
|
||||
'MCP-created session visibility toggle should stay in the sidebar search controls before the session list'
|
||||
);
|
||||
|
||||
assert(
|
||||
/MCP_SESSION_VISIBILITY_STORAGE_KEY\s*=\s*['"][^'"]*mcp[^'"]*session[^'"]*visibility[^'"]*['"]/.test(frontendSource),
|
||||
'MCP-created session visibility should use a stable local persistence key'
|
||||
);
|
||||
assert(
|
||||
/localStorage\.getItem\(MCP_SESSION_VISIBILITY_STORAGE_KEY\)/.test(frontendSource)
|
||||
&& /localStorage\.setItem\(MCP_SESSION_VISIBILITY_STORAGE_KEY/.test(frontendSource),
|
||||
'MCP-created session visibility preference should round-trip through localStorage'
|
||||
);
|
||||
const readPreferenceBlock = extractFunctionSource(frontendSource, 'readMcpSessionVisibilityPreference');
|
||||
const createReadPreference = new Function(
|
||||
'localStorage',
|
||||
'MCP_SESSION_VISIBILITY_STORAGE_KEY',
|
||||
`${readPreferenceBlock}; return readMcpSessionVisibilityPreference;`
|
||||
);
|
||||
assert(createReadPreference({ getItem: () => null }, 'test-key')() === true,
|
||||
'MCP-created sessions should remain visible when no preference has been stored');
|
||||
assert(createReadPreference({ getItem: () => 'false' }, 'test-key')() === false,
|
||||
'Stored hidden preference should restore hidden MCP-created sessions');
|
||||
assert(createReadPreference({ getItem: () => { throw new Error('blocked'); } }, 'test-key')() === true,
|
||||
'Unavailable localStorage should conservatively keep MCP-created sessions visible');
|
||||
assert(frontendSource.includes('const mcpSessionVisibilityToggle = $(\'#mcp-session-visibility-toggle\')'),
|
||||
'Frontend should bind the MCP-created session visibility toggle by its stable id');
|
||||
assert(
|
||||
/mcpSessionVisibilityToggle\.setAttribute\('aria-pressed',\s*[^)]*\)/.test(frontendSource),
|
||||
'MCP-created session visibility toggle should synchronize aria-pressed'
|
||||
);
|
||||
|
||||
const filterBlock = extractFunctionSource(frontendSource, 'sessionPassesMcpVisibilityFilter');
|
||||
assert(
|
||||
filterBlock.includes('normalizedSearchQuery')
|
||||
&& /if\s*\(\s*normalizedSearchQuery\s*\)\s*return true;/.test(filterBlock),
|
||||
'Non-empty sidebar search should bypass the MCP-created session visibility filter'
|
||||
);
|
||||
assert(
|
||||
/createdFromKind[\s\S]*['"]mcp['"]/.test(filterBlock),
|
||||
'MCP-created session visibility filter should detect sessions createdFromKind=mcp'
|
||||
);
|
||||
assert(
|
||||
filterBlock.includes('session.id === currentSessionId') && filterBlock.includes('session.isRunning'),
|
||||
'MCP-created session visibility filter should keep the current session and running sessions visible'
|
||||
);
|
||||
const createVisibilityFilter = new Function(
|
||||
'showMcpSessions',
|
||||
'currentSessionId',
|
||||
`${filterBlock}; return sessionPassesMcpVisibilityFilter;`
|
||||
);
|
||||
const hiddenFilter = createVisibilityFilter(false, 'mcp-current');
|
||||
const visibleFilter = createVisibilityFilter(true, 'mcp-current');
|
||||
const regularSession = { id: 'regular', createdFromKind: 'user', isRunning: false };
|
||||
const hiddenMcpSession = { id: 'mcp-hidden', createdFromKind: 'mcp', isRunning: false };
|
||||
const pinnedMcpSession = { ...hiddenMcpSession, id: 'mcp-pinned', pinnedAt: '2026-08-26T00:00:00.000Z' };
|
||||
const currentMcpSession = { ...hiddenMcpSession, id: 'mcp-current' };
|
||||
const runningMcpSession = { ...hiddenMcpSession, id: 'mcp-running', isRunning: true };
|
||||
assert(hiddenFilter(regularSession, '') === true, 'Normal sessions should stay visible while MCP-created sessions are hidden');
|
||||
assert(hiddenFilter(hiddenMcpSession, '') === false, 'Inactive MCP-created sessions should be hidden');
|
||||
assert(hiddenFilter(pinnedMcpSession, '') === false, 'Pinned MCP-created sessions should still be hidden when inactive');
|
||||
assert(hiddenFilter(currentMcpSession, '') === true, 'Current MCP-created session should stay visible');
|
||||
assert(hiddenFilter(runningMcpSession, '') === true, 'Running MCP-created session should stay visible');
|
||||
assert(hiddenFilter(hiddenMcpSession, '主动查找') === true, 'Search should temporarily restore matching MCP-created sessions');
|
||||
assert(visibleFilter(hiddenMcpSession, '') === true, 'Visible preference should keep every MCP-created session visible');
|
||||
|
||||
const toggleBindingStart = frontendSource.indexOf('if (mcpSessionVisibilityToggle) {');
|
||||
const toggleBindingEnd = frontendSource.indexOf('\n }', toggleBindingStart);
|
||||
const toggleBindingBlock = frontendSource.slice(toggleBindingStart, toggleBindingEnd);
|
||||
assert(toggleBindingStart >= 0
|
||||
&& toggleBindingBlock.includes("addEventListener('click'")
|
||||
&& toggleBindingBlock.includes('persistMcpSessionVisibilityPreference(showMcpSessions)')
|
||||
&& toggleBindingBlock.includes('renderSessionList()'),
|
||||
'MCP-created session visibility toggle should persist the new preference and rerender the sidebar');
|
||||
|
||||
const renderSessionListBlock = extractFunctionSource(frontendSource, 'renderSessionList');
|
||||
assert(
|
||||
renderSessionListBlock.includes('sessionPassesMcpVisibilityFilter(session, normalizedSearchQuery)'),
|
||||
'Session list rendering should apply the MCP-created session visibility filter with the current search query'
|
||||
);
|
||||
|
||||
const baseToggleStyle = styleSource.match(/\.mcp-session-visibility-toggle\s*\{[^}]*\}/)?.[0] || '';
|
||||
assert(
|
||||
/width:\s*34px;/.test(baseToggleStyle)
|
||||
&& /height:\s*34px;/.test(baseToggleStyle)
|
||||
&& /flex-basis:\s*34px;/.test(baseToggleStyle),
|
||||
'Base MCP-created session visibility toggle should keep a stable 34px square footprint'
|
||||
);
|
||||
assert(
|
||||
/html\[data-theme='wasteland'\] \.mcp-session-visibility-toggle\s*\{[^}]*width:\s*36px;[^}]*height:\s*36px;[^}]*flex-basis:\s*36px;/.test(styleSource),
|
||||
'Wasteland MCP-created session visibility toggle should align to the 36px search row controls'
|
||||
);
|
||||
}
|
||||
|
||||
function assertAdvancedSessionSearchContract() {
|
||||
const serverSource = fs.readFileSync(SERVER_PATH, 'utf8');
|
||||
const frontendSource = fs.readFileSync(PUBLIC_APP_PATH, 'utf8');
|
||||
@@ -6352,6 +6466,11 @@ async function main() {
|
||||
console.log('Advanced session search regression checks passed.');
|
||||
return;
|
||||
}
|
||||
if (regressionTarget === 'mcp-session-visibility') {
|
||||
assertMcpSessionVisibilityContract();
|
||||
console.log('MCP session visibility regression checks passed.');
|
||||
return;
|
||||
}
|
||||
if (regressionTarget === 'session-preview-metadata') {
|
||||
assertCcwebListConversationsScopeContract();
|
||||
await runSessionPreviewMetadataRegression();
|
||||
@@ -6425,6 +6544,7 @@ async function main() {
|
||||
assertSessionSwitchResilienceContract();
|
||||
assertCodexAppGoalLifecycleContract();
|
||||
assertSessionSwitchRaceContract();
|
||||
assertMcpSessionVisibilityContract();
|
||||
assertAdvancedSessionSearchContract();
|
||||
await assertAdvancedSearchTimeOrderingContract();
|
||||
assertUsageStatisticsUnitChecks();
|
||||
|
||||
Reference in New Issue
Block a user