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();
|
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 () => {
|
it('preserves enabledTools when saving config (Codex)', async () => {
|
||||||
const { CcwToolsMcpCard } = await import('./CcwToolsMcpCard');
|
const { CcwToolsMcpCard } = await import('./CcwToolsMcpCard');
|
||||||
const updateCodexMock = vi.mocked(apiMock.updateCcwConfigForCodex);
|
const updateCodexMock = vi.mocked(apiMock.updateCcwConfigForCodex);
|
||||||
|
|||||||
@@ -4371,7 +4371,9 @@ function buildCcwMcpServerConfig(config: {
|
|||||||
}): { command: string; args: string[]; env: Record<string, string> } {
|
}): { command: string; args: string[]; env: Record<string, string> } {
|
||||||
const 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(',');
|
env.CCW_ENABLED_TOOLS = config.enabledTools.join(',');
|
||||||
} else {
|
} else {
|
||||||
env.CCW_ENABLED_TOOLS = 'write_file,edit_file,read_file,core_memory,ask_question,smart_search';
|
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
|
// 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 env = ccwServer.env || {};
|
||||||
const enabledToolsStr = env.CCW_ENABLED_TOOLS || 'all';
|
const enabledToolsStr = env.CCW_ENABLED_TOOLS;
|
||||||
const enabledTools = enabledToolsStr === 'all'
|
let enabledTools: string[];
|
||||||
? ['write_file', 'edit_file', 'read_file', 'core_memory', 'ask_question']
|
if (enabledToolsStr === undefined || enabledToolsStr === null) {
|
||||||
: enabledToolsStr.split(',').map((t: string) => t.trim());
|
// 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 {
|
return {
|
||||||
isInstalled: true,
|
isInstalled: true,
|
||||||
@@ -4601,10 +4612,19 @@ export async function fetchCcwMcpConfigForCodex(): Promise<CcwMcpConfig> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const env = ccwServer.env || {};
|
const env = ccwServer.env || {};
|
||||||
const enabledToolsStr = env.CCW_ENABLED_TOOLS || 'all';
|
// Note: CCW_ENABLED_TOOLS can be empty string (all tools disabled), 'all' (default set), or comma-separated list
|
||||||
const enabledTools = enabledToolsStr === 'all'
|
const enabledToolsStr = env.CCW_ENABLED_TOOLS;
|
||||||
? ['write_file', 'edit_file', 'read_file', 'core_memory', 'ask_question', 'smart_search']
|
let enabledTools: string[];
|
||||||
: enabledToolsStr.split(',').map((t: string) => t.trim());
|
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 {
|
return {
|
||||||
isInstalled: true,
|
isInstalled: true,
|
||||||
@@ -4630,7 +4650,9 @@ function buildCcwMcpServerConfigForCodex(config: {
|
|||||||
}): { command: string; args: string[]; env: Record<string, string> } {
|
}): { command: string; args: string[]; env: Record<string, string> } {
|
||||||
const 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(',');
|
env.CCW_ENABLED_TOOLS = config.enabledTools.join(',');
|
||||||
} else {
|
} else {
|
||||||
env.CCW_ENABLED_TOOLS = 'write_file,edit_file,read_file,core_memory,ask_question,smart_search';
|
env.CCW_ENABLED_TOOLS = 'write_file,edit_file,read_file,core_memory,ask_question,smart_search';
|
||||||
|
|||||||
@@ -195,10 +195,22 @@ export const useQueueSchedulerStore = create<QueueSchedulerStore>()(
|
|||||||
'loadInitialState'
|
'loadInitialState'
|
||||||
);
|
);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
// Silently ignore network errors (backend not connected)
|
||||||
|
// Only log non-network errors
|
||||||
const message = error instanceof Error ? error.message : 'Unknown error';
|
const message = error instanceof Error ? error.message : 'Unknown 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);
|
console.error('[QueueScheduler] loadInitialState error:', message);
|
||||||
set({ error: message }, false, 'loadInitialState/error');
|
set({ error: message }, false, 'loadInitialState/error');
|
||||||
}
|
}
|
||||||
|
// For network errors, keep state as-is without showing error
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
startQueue: async (items?: QueueItem[]) => {
|
startQueue: async (items?: QueueItem[]) => {
|
||||||
|
|||||||
@@ -100,14 +100,16 @@ export async function handleAuthRoutes(ctx: RouteContext): Promise<boolean> {
|
|||||||
} else {
|
} else {
|
||||||
// Batch token response (pool pattern)
|
// Batch token response (pool pattern)
|
||||||
const tokens = tokenManager.generateTokens(sessionId, count);
|
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
|
// Set header and cookie with first token for compatibility
|
||||||
res.setHeader('X-CSRF-Token', firstToken);
|
res.setHeader('X-CSRF-Token', firstToken);
|
||||||
setCsrfCookie(res, firstToken, 15 * 60);
|
setCsrfCookie(res, firstToken, 15 * 60);
|
||||||
res.writeHead(200, { 'Content-Type': 'application/json; charset=utf-8' });
|
res.writeHead(200, { 'Content-Type': 'application/json; charset=utf-8' });
|
||||||
res.end(JSON.stringify({
|
res.end(JSON.stringify({
|
||||||
tokens,
|
tokens: tokens.length > 0 ? tokens : [firstToken],
|
||||||
expiresIn: 15 * 60, // seconds
|
expiresIn: 15 * 60, // seconds
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,53 +8,53 @@ Project-URL: Homepage, https://github.com/openai/codex-lens
|
|||||||
Requires-Python: >=3.10
|
Requires-Python: >=3.10
|
||||||
Description-Content-Type: text/markdown
|
Description-Content-Type: text/markdown
|
||||||
License-File: LICENSE
|
License-File: LICENSE
|
||||||
Requires-Dist: typer>=0.9
|
Requires-Dist: typer~=0.9.0
|
||||||
Requires-Dist: rich>=13
|
Requires-Dist: rich~=13.0.0
|
||||||
Requires-Dist: pydantic>=2.0
|
Requires-Dist: pydantic~=2.0.0
|
||||||
Requires-Dist: tree-sitter>=0.20
|
Requires-Dist: tree-sitter~=0.20.0
|
||||||
Requires-Dist: tree-sitter-python>=0.25
|
Requires-Dist: tree-sitter-python~=0.25.0
|
||||||
Requires-Dist: tree-sitter-javascript>=0.25
|
Requires-Dist: tree-sitter-javascript~=0.25.0
|
||||||
Requires-Dist: tree-sitter-typescript>=0.23
|
Requires-Dist: tree-sitter-typescript~=0.23.0
|
||||||
Requires-Dist: pathspec>=0.11
|
Requires-Dist: pathspec~=0.11.0
|
||||||
Requires-Dist: watchdog>=3.0
|
Requires-Dist: watchdog~=3.0.0
|
||||||
Requires-Dist: ast-grep-py>=0.40.0
|
Requires-Dist: ast-grep-py~=0.40.0
|
||||||
Provides-Extra: semantic
|
Provides-Extra: semantic
|
||||||
Requires-Dist: numpy>=1.24; extra == "semantic"
|
Requires-Dist: numpy~=1.24.0; extra == "semantic"
|
||||||
Requires-Dist: fastembed>=0.2; extra == "semantic"
|
Requires-Dist: fastembed~=0.2.0; extra == "semantic"
|
||||||
Requires-Dist: hnswlib>=0.8.0; extra == "semantic"
|
Requires-Dist: hnswlib~=0.8.0; extra == "semantic"
|
||||||
Provides-Extra: semantic-gpu
|
Provides-Extra: semantic-gpu
|
||||||
Requires-Dist: numpy>=1.24; extra == "semantic-gpu"
|
Requires-Dist: numpy~=1.24.0; extra == "semantic-gpu"
|
||||||
Requires-Dist: fastembed>=0.2; extra == "semantic-gpu"
|
Requires-Dist: fastembed~=0.2.0; extra == "semantic-gpu"
|
||||||
Requires-Dist: hnswlib>=0.8.0; extra == "semantic-gpu"
|
Requires-Dist: hnswlib~=0.8.0; extra == "semantic-gpu"
|
||||||
Requires-Dist: onnxruntime-gpu>=1.15.0; extra == "semantic-gpu"
|
Requires-Dist: onnxruntime-gpu~=1.15.0; extra == "semantic-gpu"
|
||||||
Provides-Extra: semantic-directml
|
Provides-Extra: semantic-directml
|
||||||
Requires-Dist: numpy>=1.24; extra == "semantic-directml"
|
Requires-Dist: numpy~=1.24.0; extra == "semantic-directml"
|
||||||
Requires-Dist: fastembed>=0.2; extra == "semantic-directml"
|
Requires-Dist: fastembed~=0.2.0; extra == "semantic-directml"
|
||||||
Requires-Dist: hnswlib>=0.8.0; extra == "semantic-directml"
|
Requires-Dist: hnswlib~=0.8.0; extra == "semantic-directml"
|
||||||
Requires-Dist: onnxruntime-directml>=1.15.0; extra == "semantic-directml"
|
Requires-Dist: onnxruntime-directml~=1.15.0; extra == "semantic-directml"
|
||||||
Provides-Extra: reranker-onnx
|
Provides-Extra: reranker-onnx
|
||||||
Requires-Dist: optimum>=1.16; extra == "reranker-onnx"
|
Requires-Dist: optimum~=1.16.0; extra == "reranker-onnx"
|
||||||
Requires-Dist: onnxruntime>=1.15; extra == "reranker-onnx"
|
Requires-Dist: onnxruntime~=1.15.0; extra == "reranker-onnx"
|
||||||
Requires-Dist: transformers>=4.36; extra == "reranker-onnx"
|
Requires-Dist: transformers~=4.36.0; extra == "reranker-onnx"
|
||||||
Provides-Extra: reranker-api
|
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
|
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
|
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
|
Provides-Extra: reranker
|
||||||
Requires-Dist: optimum>=1.16; extra == "reranker"
|
Requires-Dist: optimum~=1.16.0; extra == "reranker"
|
||||||
Requires-Dist: onnxruntime>=1.15; extra == "reranker"
|
Requires-Dist: onnxruntime~=1.15.0; extra == "reranker"
|
||||||
Requires-Dist: transformers>=4.36; extra == "reranker"
|
Requires-Dist: transformers~=4.36.0; extra == "reranker"
|
||||||
Provides-Extra: encoding
|
Provides-Extra: encoding
|
||||||
Requires-Dist: chardet>=5.0; extra == "encoding"
|
Requires-Dist: chardet~=5.0.0; extra == "encoding"
|
||||||
Provides-Extra: clustering
|
Provides-Extra: clustering
|
||||||
Requires-Dist: hdbscan>=0.8.1; extra == "clustering"
|
Requires-Dist: hdbscan~=0.8.1; extra == "clustering"
|
||||||
Requires-Dist: scikit-learn>=1.3.0; extra == "clustering"
|
Requires-Dist: scikit-learn~=1.3.0; extra == "clustering"
|
||||||
Provides-Extra: full
|
Provides-Extra: full
|
||||||
Requires-Dist: tiktoken>=0.5.0; extra == "full"
|
Requires-Dist: tiktoken~=0.5.0; extra == "full"
|
||||||
Provides-Extra: lsp
|
Provides-Extra: lsp
|
||||||
Requires-Dist: pygls>=1.3.0; extra == "lsp"
|
Requires-Dist: pygls~=1.3.0; extra == "lsp"
|
||||||
Dynamic: license-file
|
Dynamic: license-file
|
||||||
|
|
||||||
# CodexLens
|
# CodexLens
|
||||||
|
|||||||
@@ -153,10 +153,12 @@ tests/test_hybrid_chunker.py
|
|||||||
tests/test_hybrid_search_e2e.py
|
tests/test_hybrid_search_e2e.py
|
||||||
tests/test_hybrid_search_reranker_backend.py
|
tests/test_hybrid_search_reranker_backend.py
|
||||||
tests/test_hybrid_search_unit.py
|
tests/test_hybrid_search_unit.py
|
||||||
|
tests/test_incremental_indexer.py
|
||||||
tests/test_incremental_indexing.py
|
tests/test_incremental_indexing.py
|
||||||
tests/test_litellm_reranker.py
|
tests/test_litellm_reranker.py
|
||||||
tests/test_lsp_graph_builder_depth.py
|
tests/test_lsp_graph_builder_depth.py
|
||||||
tests/test_merkle_detection.py
|
tests/test_merkle_detection.py
|
||||||
|
tests/test_migrations.py
|
||||||
tests/test_parser_integration.py
|
tests/test_parser_integration.py
|
||||||
tests/test_parsers.py
|
tests/test_parsers.py
|
||||||
tests/test_path_mapper_windows_drive.py
|
tests/test_path_mapper_windows_drive.py
|
||||||
|
|||||||
@@ -1,59 +1,59 @@
|
|||||||
typer>=0.9
|
typer~=0.9.0
|
||||||
rich>=13
|
rich~=13.0.0
|
||||||
pydantic>=2.0
|
pydantic~=2.0.0
|
||||||
tree-sitter>=0.20
|
tree-sitter~=0.20.0
|
||||||
tree-sitter-python>=0.25
|
tree-sitter-python~=0.25.0
|
||||||
tree-sitter-javascript>=0.25
|
tree-sitter-javascript~=0.25.0
|
||||||
tree-sitter-typescript>=0.23
|
tree-sitter-typescript~=0.23.0
|
||||||
pathspec>=0.11
|
pathspec~=0.11.0
|
||||||
watchdog>=3.0
|
watchdog~=3.0.0
|
||||||
ast-grep-py>=0.40.0
|
ast-grep-py~=0.40.0
|
||||||
|
|
||||||
[clustering]
|
[clustering]
|
||||||
hdbscan>=0.8.1
|
hdbscan~=0.8.1
|
||||||
scikit-learn>=1.3.0
|
scikit-learn~=1.3.0
|
||||||
|
|
||||||
[encoding]
|
[encoding]
|
||||||
chardet>=5.0
|
chardet~=5.0.0
|
||||||
|
|
||||||
[full]
|
[full]
|
||||||
tiktoken>=0.5.0
|
tiktoken~=0.5.0
|
||||||
|
|
||||||
[lsp]
|
[lsp]
|
||||||
pygls>=1.3.0
|
pygls~=1.3.0
|
||||||
|
|
||||||
[reranker]
|
[reranker]
|
||||||
optimum>=1.16
|
optimum~=1.16.0
|
||||||
onnxruntime>=1.15
|
onnxruntime~=1.15.0
|
||||||
transformers>=4.36
|
transformers~=4.36.0
|
||||||
|
|
||||||
[reranker-api]
|
[reranker-api]
|
||||||
httpx>=0.25
|
httpx~=0.25.0
|
||||||
|
|
||||||
[reranker-legacy]
|
[reranker-legacy]
|
||||||
sentence-transformers>=2.2
|
sentence-transformers~=2.2.0
|
||||||
|
|
||||||
[reranker-litellm]
|
[reranker-litellm]
|
||||||
ccw-litellm>=0.1
|
ccw-litellm~=0.1.0
|
||||||
|
|
||||||
[reranker-onnx]
|
[reranker-onnx]
|
||||||
optimum>=1.16
|
optimum~=1.16.0
|
||||||
onnxruntime>=1.15
|
onnxruntime~=1.15.0
|
||||||
transformers>=4.36
|
transformers~=4.36.0
|
||||||
|
|
||||||
[semantic]
|
[semantic]
|
||||||
numpy>=1.24
|
numpy~=1.24.0
|
||||||
fastembed>=0.2
|
fastembed~=0.2.0
|
||||||
hnswlib>=0.8.0
|
hnswlib~=0.8.0
|
||||||
|
|
||||||
[semantic-directml]
|
[semantic-directml]
|
||||||
numpy>=1.24
|
numpy~=1.24.0
|
||||||
fastembed>=0.2
|
fastembed~=0.2.0
|
||||||
hnswlib>=0.8.0
|
hnswlib~=0.8.0
|
||||||
onnxruntime-directml>=1.15.0
|
onnxruntime-directml~=1.15.0
|
||||||
|
|
||||||
[semantic-gpu]
|
[semantic-gpu]
|
||||||
numpy>=1.24
|
numpy~=1.24.0
|
||||||
fastembed>=0.2
|
fastembed~=0.2.0
|
||||||
hnswlib>=0.8.0
|
hnswlib~=0.8.0
|
||||||
onnxruntime-gpu>=1.15.0
|
onnxruntime-gpu~=1.15.0
|
||||||
|
|||||||
Reference in New Issue
Block a user