diff --git a/ccw/frontend/src/components/mcp/CcwToolsMcpCard.test.tsx b/ccw/frontend/src/components/mcp/CcwToolsMcpCard.test.tsx index 9ead3b49..455b8d5e 100644 --- a/ccw/frontend/src/components/mcp/CcwToolsMcpCard.test.tsx +++ b/ccw/frontend/src/components/mcp/CcwToolsMcpCard.test.tsx @@ -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( + , + { 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); diff --git a/ccw/frontend/src/lib/api.ts b/ccw/frontend/src/lib/api.ts index 58abdfbc..645d166c 100644 --- a/ccw/frontend/src/lib/api.ts +++ b/ccw/frontend/src/lib/api.ts @@ -4371,7 +4371,9 @@ function buildCcwMcpServerConfig(config: { }): { command: string; args: string[]; env: Record } { const env: Record = {}; - 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 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 { } 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 } { const env: Record = {}; - 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'; diff --git a/ccw/frontend/src/stores/queueSchedulerStore.ts b/ccw/frontend/src/stores/queueSchedulerStore.ts index 72317867..2c20b617 100644 --- a/ccw/frontend/src/stores/queueSchedulerStore.ts +++ b/ccw/frontend/src/stores/queueSchedulerStore.ts @@ -195,9 +195,21 @@ export const useQueueSchedulerStore = create()( '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 } }, diff --git a/ccw/src/core/routes/auth-routes.ts b/ccw/src/core/routes/auth-routes.ts index b5b1613b..b3d3559a 100644 --- a/ccw/src/core/routes/auth-routes.ts +++ b/ccw/src/core/routes/auth-routes.ts @@ -100,14 +100,16 @@ export async function handleAuthRoutes(ctx: RouteContext): Promise { } else { // Batch token response (pool pattern) const tokens = tokenManager.generateTokens(sessionId, count); - const firstToken = tokens[0]; + + // If no tokens generated (session at max capacity), force generate one + const firstToken = tokens.length > 0 ? tokens[0] : tokenManager.generateToken(sessionId); // Set header and cookie with first token for compatibility res.setHeader('X-CSRF-Token', firstToken); setCsrfCookie(res, firstToken, 15 * 60); res.writeHead(200, { 'Content-Type': 'application/json; charset=utf-8' }); res.end(JSON.stringify({ - tokens, + tokens: tokens.length > 0 ? tokens : [firstToken], expiresIn: 15 * 60, // seconds })); } diff --git a/codex-lens/src/codex_lens.egg-info/PKG-INFO b/codex-lens/src/codex_lens.egg-info/PKG-INFO index 947ba20f..1cffe19e 100644 --- a/codex-lens/src/codex_lens.egg-info/PKG-INFO +++ b/codex-lens/src/codex_lens.egg-info/PKG-INFO @@ -8,53 +8,53 @@ Project-URL: Homepage, https://github.com/openai/codex-lens Requires-Python: >=3.10 Description-Content-Type: text/markdown License-File: LICENSE -Requires-Dist: typer>=0.9 -Requires-Dist: rich>=13 -Requires-Dist: pydantic>=2.0 -Requires-Dist: tree-sitter>=0.20 -Requires-Dist: tree-sitter-python>=0.25 -Requires-Dist: tree-sitter-javascript>=0.25 -Requires-Dist: tree-sitter-typescript>=0.23 -Requires-Dist: pathspec>=0.11 -Requires-Dist: watchdog>=3.0 -Requires-Dist: ast-grep-py>=0.40.0 +Requires-Dist: typer~=0.9.0 +Requires-Dist: rich~=13.0.0 +Requires-Dist: pydantic~=2.0.0 +Requires-Dist: tree-sitter~=0.20.0 +Requires-Dist: tree-sitter-python~=0.25.0 +Requires-Dist: tree-sitter-javascript~=0.25.0 +Requires-Dist: tree-sitter-typescript~=0.23.0 +Requires-Dist: pathspec~=0.11.0 +Requires-Dist: watchdog~=3.0.0 +Requires-Dist: ast-grep-py~=0.40.0 Provides-Extra: semantic -Requires-Dist: numpy>=1.24; extra == "semantic" -Requires-Dist: fastembed>=0.2; extra == "semantic" -Requires-Dist: hnswlib>=0.8.0; extra == "semantic" +Requires-Dist: numpy~=1.24.0; extra == "semantic" +Requires-Dist: fastembed~=0.2.0; extra == "semantic" +Requires-Dist: hnswlib~=0.8.0; extra == "semantic" Provides-Extra: semantic-gpu -Requires-Dist: numpy>=1.24; extra == "semantic-gpu" -Requires-Dist: fastembed>=0.2; extra == "semantic-gpu" -Requires-Dist: hnswlib>=0.8.0; extra == "semantic-gpu" -Requires-Dist: onnxruntime-gpu>=1.15.0; extra == "semantic-gpu" +Requires-Dist: numpy~=1.24.0; extra == "semantic-gpu" +Requires-Dist: fastembed~=0.2.0; extra == "semantic-gpu" +Requires-Dist: hnswlib~=0.8.0; extra == "semantic-gpu" +Requires-Dist: onnxruntime-gpu~=1.15.0; extra == "semantic-gpu" Provides-Extra: semantic-directml -Requires-Dist: numpy>=1.24; extra == "semantic-directml" -Requires-Dist: fastembed>=0.2; extra == "semantic-directml" -Requires-Dist: hnswlib>=0.8.0; extra == "semantic-directml" -Requires-Dist: onnxruntime-directml>=1.15.0; extra == "semantic-directml" +Requires-Dist: numpy~=1.24.0; extra == "semantic-directml" +Requires-Dist: fastembed~=0.2.0; extra == "semantic-directml" +Requires-Dist: hnswlib~=0.8.0; extra == "semantic-directml" +Requires-Dist: onnxruntime-directml~=1.15.0; extra == "semantic-directml" Provides-Extra: reranker-onnx -Requires-Dist: optimum>=1.16; extra == "reranker-onnx" -Requires-Dist: onnxruntime>=1.15; extra == "reranker-onnx" -Requires-Dist: transformers>=4.36; extra == "reranker-onnx" +Requires-Dist: optimum~=1.16.0; extra == "reranker-onnx" +Requires-Dist: onnxruntime~=1.15.0; extra == "reranker-onnx" +Requires-Dist: transformers~=4.36.0; extra == "reranker-onnx" Provides-Extra: reranker-api -Requires-Dist: httpx>=0.25; extra == "reranker-api" +Requires-Dist: httpx~=0.25.0; extra == "reranker-api" Provides-Extra: reranker-litellm -Requires-Dist: ccw-litellm>=0.1; extra == "reranker-litellm" +Requires-Dist: ccw-litellm~=0.1.0; extra == "reranker-litellm" Provides-Extra: reranker-legacy -Requires-Dist: sentence-transformers>=2.2; extra == "reranker-legacy" +Requires-Dist: sentence-transformers~=2.2.0; extra == "reranker-legacy" Provides-Extra: reranker -Requires-Dist: optimum>=1.16; extra == "reranker" -Requires-Dist: onnxruntime>=1.15; extra == "reranker" -Requires-Dist: transformers>=4.36; extra == "reranker" +Requires-Dist: optimum~=1.16.0; extra == "reranker" +Requires-Dist: onnxruntime~=1.15.0; extra == "reranker" +Requires-Dist: transformers~=4.36.0; extra == "reranker" Provides-Extra: encoding -Requires-Dist: chardet>=5.0; extra == "encoding" +Requires-Dist: chardet~=5.0.0; extra == "encoding" Provides-Extra: clustering -Requires-Dist: hdbscan>=0.8.1; extra == "clustering" -Requires-Dist: scikit-learn>=1.3.0; extra == "clustering" +Requires-Dist: hdbscan~=0.8.1; extra == "clustering" +Requires-Dist: scikit-learn~=1.3.0; extra == "clustering" Provides-Extra: full -Requires-Dist: tiktoken>=0.5.0; extra == "full" +Requires-Dist: tiktoken~=0.5.0; extra == "full" Provides-Extra: lsp -Requires-Dist: pygls>=1.3.0; extra == "lsp" +Requires-Dist: pygls~=1.3.0; extra == "lsp" Dynamic: license-file # CodexLens diff --git a/codex-lens/src/codex_lens.egg-info/SOURCES.txt b/codex-lens/src/codex_lens.egg-info/SOURCES.txt index dd7bf022..b84f547e 100644 --- a/codex-lens/src/codex_lens.egg-info/SOURCES.txt +++ b/codex-lens/src/codex_lens.egg-info/SOURCES.txt @@ -153,10 +153,12 @@ tests/test_hybrid_chunker.py tests/test_hybrid_search_e2e.py tests/test_hybrid_search_reranker_backend.py tests/test_hybrid_search_unit.py +tests/test_incremental_indexer.py tests/test_incremental_indexing.py tests/test_litellm_reranker.py tests/test_lsp_graph_builder_depth.py tests/test_merkle_detection.py +tests/test_migrations.py tests/test_parser_integration.py tests/test_parsers.py tests/test_path_mapper_windows_drive.py diff --git a/codex-lens/src/codex_lens.egg-info/requires.txt b/codex-lens/src/codex_lens.egg-info/requires.txt index d15ba892..a4f28711 100644 --- a/codex-lens/src/codex_lens.egg-info/requires.txt +++ b/codex-lens/src/codex_lens.egg-info/requires.txt @@ -1,59 +1,59 @@ -typer>=0.9 -rich>=13 -pydantic>=2.0 -tree-sitter>=0.20 -tree-sitter-python>=0.25 -tree-sitter-javascript>=0.25 -tree-sitter-typescript>=0.23 -pathspec>=0.11 -watchdog>=3.0 -ast-grep-py>=0.40.0 +typer~=0.9.0 +rich~=13.0.0 +pydantic~=2.0.0 +tree-sitter~=0.20.0 +tree-sitter-python~=0.25.0 +tree-sitter-javascript~=0.25.0 +tree-sitter-typescript~=0.23.0 +pathspec~=0.11.0 +watchdog~=3.0.0 +ast-grep-py~=0.40.0 [clustering] -hdbscan>=0.8.1 -scikit-learn>=1.3.0 +hdbscan~=0.8.1 +scikit-learn~=1.3.0 [encoding] -chardet>=5.0 +chardet~=5.0.0 [full] -tiktoken>=0.5.0 +tiktoken~=0.5.0 [lsp] -pygls>=1.3.0 +pygls~=1.3.0 [reranker] -optimum>=1.16 -onnxruntime>=1.15 -transformers>=4.36 +optimum~=1.16.0 +onnxruntime~=1.15.0 +transformers~=4.36.0 [reranker-api] -httpx>=0.25 +httpx~=0.25.0 [reranker-legacy] -sentence-transformers>=2.2 +sentence-transformers~=2.2.0 [reranker-litellm] -ccw-litellm>=0.1 +ccw-litellm~=0.1.0 [reranker-onnx] -optimum>=1.16 -onnxruntime>=1.15 -transformers>=4.36 +optimum~=1.16.0 +onnxruntime~=1.15.0 +transformers~=4.36.0 [semantic] -numpy>=1.24 -fastembed>=0.2 -hnswlib>=0.8.0 +numpy~=1.24.0 +fastembed~=0.2.0 +hnswlib~=0.8.0 [semantic-directml] -numpy>=1.24 -fastembed>=0.2 -hnswlib>=0.8.0 -onnxruntime-directml>=1.15.0 +numpy~=1.24.0 +fastembed~=0.2.0 +hnswlib~=0.8.0 +onnxruntime-directml~=1.15.0 [semantic-gpu] -numpy>=1.24 -fastembed>=0.2 -hnswlib>=0.8.0 -onnxruntime-gpu>=1.15.0 +numpy~=1.24.0 +fastembed~=0.2.0 +hnswlib~=0.8.0 +onnxruntime-gpu~=1.15.0