mirror of
https://github.com/catlog22/Claude-Code-Workflow.git
synced 2026-03-02 15:23:19 +08:00
fix(tests): add test for disabling all tools in CcwToolsMcpCard component
fix(api): handle empty enabledTools array and improve default tool logic fix(queueScheduler): ignore network errors in loadInitialState fix(auth): ensure token generation handles max session capacity chore(dependencies): update package requirements to use compatible version specifiers chore(tests): add new test cases for incremental indexer and migrations
This commit is contained in:
@@ -41,6 +41,43 @@ describe('CcwToolsMcpCard', () => {
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
|
||||
it('disables all tools when clicking "Disable All" button', async () => {
|
||||
const { CcwToolsMcpCard } = await import('./CcwToolsMcpCard');
|
||||
const onUpdateConfigMock = vi.fn();
|
||||
|
||||
render(
|
||||
<CcwToolsMcpCard
|
||||
target="codex"
|
||||
isInstalled={true}
|
||||
enabledTools={['write_file', 'read_file', 'edit_file']}
|
||||
onToggleTool={vi.fn()}
|
||||
onUpdateConfig={onUpdateConfigMock}
|
||||
onInstall={vi.fn()}
|
||||
/>,
|
||||
{ locale: 'en' }
|
||||
);
|
||||
|
||||
const user = userEvent.setup();
|
||||
// Expand the card
|
||||
await act(async () => {
|
||||
await user.click(screen.getByText(/CCW MCP Server|mcp\.ccw\.title/i));
|
||||
});
|
||||
|
||||
// Find and click "Disable All" button
|
||||
const disableAllButton = screen.getByRole('button', {
|
||||
name: /Disable All|mcp\.ccw\.actions\.disableAll/i,
|
||||
});
|
||||
expect(disableAllButton).toBeEnabled();
|
||||
await act(async () => {
|
||||
await user.click(disableAllButton);
|
||||
});
|
||||
|
||||
// Verify onUpdateConfig was called with empty enabledTools array
|
||||
await waitFor(() => {
|
||||
expect(onUpdateConfigMock).toHaveBeenCalledWith({ enabledTools: [] });
|
||||
});
|
||||
});
|
||||
|
||||
it('preserves enabledTools when saving config (Codex)', async () => {
|
||||
const { CcwToolsMcpCard } = await import('./CcwToolsMcpCard');
|
||||
const updateCodexMock = vi.mocked(apiMock.updateCcwConfigForCodex);
|
||||
|
||||
@@ -4371,7 +4371,9 @@ function buildCcwMcpServerConfig(config: {
|
||||
}): { command: string; args: string[]; env: Record<string, string> } {
|
||||
const env: Record<string, string> = {};
|
||||
|
||||
if (config.enabledTools && config.enabledTools.length > 0) {
|
||||
// Only use default when enabledTools is undefined (not provided)
|
||||
// When enabledTools is an empty array, set to empty string to disable all tools
|
||||
if (config.enabledTools !== undefined) {
|
||||
env.CCW_ENABLED_TOOLS = config.enabledTools.join(',');
|
||||
} else {
|
||||
env.CCW_ENABLED_TOOLS = 'write_file,edit_file,read_file,core_memory,ask_question,smart_search';
|
||||
@@ -4455,11 +4457,20 @@ export async function fetchCcwMcpConfig(currentProjectPath?: string): Promise<Cc
|
||||
}
|
||||
|
||||
// Parse enabled tools from env
|
||||
// Note: CCW_ENABLED_TOOLS can be empty string (all tools disabled), 'all' (default set), or comma-separated list
|
||||
const env = ccwServer.env || {};
|
||||
const enabledToolsStr = env.CCW_ENABLED_TOOLS || 'all';
|
||||
const enabledTools = enabledToolsStr === 'all'
|
||||
? ['write_file', 'edit_file', 'read_file', 'core_memory', 'ask_question']
|
||||
: enabledToolsStr.split(',').map((t: string) => t.trim());
|
||||
const enabledToolsStr = env.CCW_ENABLED_TOOLS;
|
||||
let enabledTools: string[];
|
||||
if (enabledToolsStr === undefined || enabledToolsStr === null) {
|
||||
// No setting = use default tools
|
||||
enabledTools = ['write_file', 'edit_file', 'read_file', 'core_memory', 'ask_question', 'smart_search'];
|
||||
} else if (enabledToolsStr === '' || enabledToolsStr === 'all') {
|
||||
// Empty string = all tools disabled, 'all' = default set (for backward compatibility)
|
||||
enabledTools = enabledToolsStr === '' ? [] : ['write_file', 'edit_file', 'read_file', 'core_memory', 'ask_question', 'smart_search'];
|
||||
} else {
|
||||
// Comma-separated list
|
||||
enabledTools = enabledToolsStr.split(',').map((t: string) => t.trim()).filter(Boolean);
|
||||
}
|
||||
|
||||
return {
|
||||
isInstalled: true,
|
||||
@@ -4601,10 +4612,19 @@ export async function fetchCcwMcpConfigForCodex(): Promise<CcwMcpConfig> {
|
||||
}
|
||||
|
||||
const env = ccwServer.env || {};
|
||||
const enabledToolsStr = env.CCW_ENABLED_TOOLS || 'all';
|
||||
const enabledTools = enabledToolsStr === 'all'
|
||||
? ['write_file', 'edit_file', 'read_file', 'core_memory', 'ask_question', 'smart_search']
|
||||
: enabledToolsStr.split(',').map((t: string) => t.trim());
|
||||
// Note: CCW_ENABLED_TOOLS can be empty string (all tools disabled), 'all' (default set), or comma-separated list
|
||||
const enabledToolsStr = env.CCW_ENABLED_TOOLS;
|
||||
let enabledTools: string[];
|
||||
if (enabledToolsStr === undefined || enabledToolsStr === null) {
|
||||
// No setting = use default tools
|
||||
enabledTools = ['write_file', 'edit_file', 'read_file', 'core_memory', 'ask_question', 'smart_search'];
|
||||
} else if (enabledToolsStr === '' || enabledToolsStr === 'all') {
|
||||
// Empty string = all tools disabled, 'all' = default set (for backward compatibility)
|
||||
enabledTools = enabledToolsStr === '' ? [] : ['write_file', 'edit_file', 'read_file', 'core_memory', 'ask_question', 'smart_search'];
|
||||
} else {
|
||||
// Comma-separated list
|
||||
enabledTools = enabledToolsStr.split(',').map((t: string) => t.trim()).filter(Boolean);
|
||||
}
|
||||
|
||||
return {
|
||||
isInstalled: true,
|
||||
@@ -4630,7 +4650,9 @@ function buildCcwMcpServerConfigForCodex(config: {
|
||||
}): { command: string; args: string[]; env: Record<string, string> } {
|
||||
const env: Record<string, string> = {};
|
||||
|
||||
if (config.enabledTools && config.enabledTools.length > 0) {
|
||||
// Only use default when enabledTools is undefined (not provided)
|
||||
// When enabledTools is an empty array, set to empty string to disable all tools
|
||||
if (config.enabledTools !== undefined) {
|
||||
env.CCW_ENABLED_TOOLS = config.enabledTools.join(',');
|
||||
} else {
|
||||
env.CCW_ENABLED_TOOLS = 'write_file,edit_file,read_file,core_memory,ask_question,smart_search';
|
||||
|
||||
@@ -195,9 +195,21 @@ export const useQueueSchedulerStore = create<QueueSchedulerStore>()(
|
||||
'loadInitialState'
|
||||
);
|
||||
} catch (error) {
|
||||
// Silently ignore network errors (backend not connected)
|
||||
// Only log non-network errors
|
||||
const message = error instanceof Error ? error.message : 'Unknown error';
|
||||
console.error('[QueueScheduler] loadInitialState error:', message);
|
||||
set({ error: message }, false, 'loadInitialState/error');
|
||||
const isNetworkError =
|
||||
message.includes('Failed to fetch') ||
|
||||
message.includes('NetworkError') ||
|
||||
message.includes('Network request failed') ||
|
||||
message.includes('ERR_CONNECTION_REFUSED') ||
|
||||
message.includes('ERR_CONNECTION_RESET');
|
||||
|
||||
if (!isNetworkError) {
|
||||
console.error('[QueueScheduler] loadInitialState error:', message);
|
||||
set({ error: message }, false, 'loadInitialState/error');
|
||||
}
|
||||
// For network errors, keep state as-is without showing error
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
Reference in New Issue
Block a user