diff --git a/.claude/commands/workflow/lite-plan.md b/.claude/commands/workflow/lite-plan.md index c10f704a..e1bc28ac 100644 --- a/.claude/commands/workflow/lite-plan.md +++ b/.claude/commands/workflow/lite-plan.md @@ -140,11 +140,17 @@ function selectAngles(taskDescription, count) { const selectedAngles = selectAngles(task_description, complexity === 'High' ? 4 : (complexity === 'Medium' ? 3 : 1)) +// Planning strategy determination +const planningStrategy = complexity === 'Low' + ? 'Direct Claude Planning' + : 'cli-lite-planning-agent' + console.log(` ## Exploration Plan Task Complexity: ${complexity} Selected Angles: ${selectedAngles.join(', ')} +Planning Strategy: ${planningStrategy} Launching ${selectedAngles.length} parallel explorations... `) @@ -358,10 +364,7 @@ if (dedupedClarifications.length > 0) { ```javascript // 分配规则(优先级从高到低): // 1. 用户明确指定:"用 gemini 分析..." → gemini, "codex 实现..." → codex -// 2. 任务类型推断: -// - 分析|审查|评估|探索 → gemini -// - 实现|创建|修改|修复 → codex (复杂) 或 agent (简单) -// 3. 默认 → agent +// 2. 默认 → agent const executorAssignments = {} // { taskId: { executor: 'gemini'|'codex'|'agent', reason: string } } plan.tasks.forEach(task => { diff --git a/.claude/workflows/context-tools-ace.md b/.claude/workflows/context-tools-ace.md new file mode 100644 index 00000000..c967bbd1 --- /dev/null +++ b/.claude/workflows/context-tools-ace.md @@ -0,0 +1,105 @@ +## MCP Tools Usage + +### search_context (ACE) - Code Search (REQUIRED - HIGHEST PRIORITY) + +**OVERRIDES**: All other search/discovery rules in other workflow files + +**When**: ANY code discovery task, including: +- Find code, understand codebase structure, locate implementations +- Explore unknown locations +- Verify file existence before reading +- Pattern-based file discovery +- Semantic code understanding + +**Priority Rule**: +1. **Always use mcp__ace-tool__search_context FIRST** for any code/file discovery +2. Only use Built-in Grep for single-file exact line search (after location confirmed) +3. Only use Built-in Read for known, confirmed file paths + +**How**: +```javascript +// Natural language code search - best for understanding and exploration +mcp__ace-tool__search_context({ + project_root_path: "/path/to/project", + query: "authentication logic" +}) + +// With keywords for better semantic matching +mcp__ace-tool__search_context({ + project_root_path: "/path/to/project", + query: "I want to find where the server handles user login. Keywords: auth, login, session" +}) +``` + +**Good Query Examples**: +- "Where is the function that handles user authentication?" +- "What tests are there for the login functionality?" +- "How is the database connected to the application?" +- "I want to find where the server handles chunk merging. Keywords: upload chunk merge" +- "Locate where the system refreshes cached data. Keywords: cache refresh, invalidation" + +**Bad Query Examples** (use grep or file view instead): +- "Find definition of constructor of class Foo" (use grep tool instead) +- "Find all references to function bar" (use grep tool instead) +- "Show me how Checkout class is used in services/payment.py" (use file view tool instead) + +**Key Features**: +- Real-time index of the codebase (always up-to-date) +- Cross-language retrieval support +- Semantic search with embeddings +- No manual index initialization required + +--- + +### read_file - Read File Contents + +**When**: Read files found by search_context + +**How**: +```javascript +read_file(path="/path/to/file.ts") // Single file +read_file(path="/src/**/*.config.ts") // Pattern matching +``` + +--- + +### edit_file - Modify Files + +**When**: Built-in Edit tool fails or need advanced features + +**How**: +```javascript +edit_file(path="/file.ts", old_string="...", new_string="...", mode="update") +edit_file(path="/file.ts", line=10, content="...", mode="insert_after") +``` + +**Modes**: `update` (replace text), `insert_after`, `insert_before`, `delete_line` + +--- + +### write_file - Create/Overwrite Files + +**When**: Create new files or completely replace content + +**How**: +```javascript +write_file(path="/new-file.ts", content="...") +``` + +--- + +### Exa - External Search + +**When**: Find documentation/examples outside codebase + +**How**: +```javascript +mcp__exa__search(query="React hooks 2025 documentation") +mcp__exa__search(query="FastAPI auth example", numResults=10) +mcp__exa__search(query="latest API docs", livecrawl="always") +``` + +**Parameters**: +- `query` (required): Search query string +- `numResults` (optional): Number of results to return (default: 5) +- `livecrawl` (optional): `"always"` or `"fallback"` for live crawling diff --git a/ccw/src/core/routes/cli-routes.ts b/ccw/src/core/routes/cli-routes.ts index 2c9a6b4d..3146adb0 100644 --- a/ccw/src/core/routes/cli-routes.ts +++ b/ccw/src/core/routes/cli-routes.ts @@ -40,7 +40,9 @@ import { updateClaudeCacheSettings, getClaudeCliToolsInfo, addClaudeCustomEndpoint, - removeClaudeCustomEndpoint + removeClaudeCustomEndpoint, + updateCodeIndexMcp, + getCodeIndexMcp } from '../../tools/claude-cli-tools.js'; export interface RouteContext { @@ -750,5 +752,45 @@ export async function handleCliRoutes(ctx: RouteContext): Promise { return true; } + // API: Get Code Index MCP provider + if (pathname === '/api/cli/code-index-mcp' && req.method === 'GET') { + try { + const provider = getCodeIndexMcp(initialPath); + res.writeHead(200, { 'Content-Type': 'application/json' }); + res.end(JSON.stringify({ provider })); + } catch (err) { + res.writeHead(500, { 'Content-Type': 'application/json' }); + res.end(JSON.stringify({ error: (err as Error).message })); + } + return true; + } + + // API: Update Code Index MCP provider + if (pathname === '/api/cli/code-index-mcp' && req.method === 'PUT') { + handlePostRequest(req, res, async (body: unknown) => { + try { + const { provider } = body as { provider: 'codexlens' | 'ace' }; + if (!provider || !['codexlens', 'ace'].includes(provider)) { + return { error: 'Invalid provider. Must be "codexlens" or "ace"', status: 400 }; + } + + const result = updateCodeIndexMcp(initialPath, provider); + + if (result.success) { + broadcastToClients({ + type: 'CODE_INDEX_MCP_UPDATED', + payload: { provider, timestamp: new Date().toISOString() } + }); + return { success: true, provider }; + } else { + return { error: result.error, status: 500 }; + } + } catch (err) { + return { error: (err as Error).message, status: 500 }; + } + }); + return true; + } + return false; } diff --git a/ccw/src/templates/dashboard-js/components/cli-status.js b/ccw/src/templates/dashboard-js/components/cli-status.js index f1f448c1..a5cab49a 100644 --- a/ccw/src/templates/dashboard-js/components/cli-status.js +++ b/ccw/src/templates/dashboard-js/components/cli-status.js @@ -21,6 +21,9 @@ let nativeResumeEnabled = localStorage.getItem('ccw-native-resume') !== 'false'; // Recursive Query settings (for hierarchical storage aggregation) let recursiveQueryEnabled = localStorage.getItem('ccw-recursive-query') !== 'false'; // default true +// Code Index MCP provider (codexlens or ace) +let codeIndexMcpProvider = 'codexlens'; + // ========== Initialization ========== function initCliStatus() { // Load all statuses in one call using aggregated endpoint @@ -241,7 +244,12 @@ async function loadCliToolsConfig() { defaultCliTool = data.defaultTool; } - console.log('[CLI Config] Loaded from:', data._configInfo?.source || 'unknown', '| Default:', data.defaultTool); + // Load Code Index MCP provider from config + if (data.settings?.codeIndexMcp) { + codeIndexMcpProvider = data.settings.codeIndexMcp; + } + + console.log('[CLI Config] Loaded from:', data._configInfo?.source || 'unknown', '| Default:', data.defaultTool, '| CodeIndexMCP:', codeIndexMcpProvider); return data; } catch (err) { console.error('Failed to load CLI tools config:', err); @@ -614,6 +622,25 @@ function renderCliStatus() {

Cache prefix/suffix injection mode for prompts

+
+ +
+
+ + +
+
+

Code search provider (updates CLAUDE.md context-tools reference)

+
`; @@ -736,6 +763,30 @@ async function setCacheInjectionMode(mode) { } } +async function setCodeIndexMcpProvider(provider) { + try { + const response = await fetch('/api/cli/code-index-mcp', { + method: 'PUT', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ provider: provider }) + }); + if (response.ok) { + codeIndexMcpProvider = provider; + if (window.claudeCliToolsConfig && window.claudeCliToolsConfig.settings) { + window.claudeCliToolsConfig.settings.codeIndexMcp = provider; + } + showRefreshToast(`Code Index MCP switched to ${provider === 'ace' ? 'ACE (Augment)' : 'CodexLens'}`, 'success'); + renderCliStatus(); + } else { + const data = await response.json(); + showRefreshToast(`Failed to switch Code Index MCP: ${data.error}`, 'error'); + } + } catch (err) { + console.error('Failed to switch Code Index MCP:', err); + showRefreshToast('Failed to switch Code Index MCP', 'error'); + } +} + async function refreshAllCliStatus() { await loadAllStatuses(); renderCliStatus(); diff --git a/ccw/src/tools/claude-cli-tools.ts b/ccw/src/tools/claude-cli-tools.ts index 77b0ce51..31c848b1 100644 --- a/ccw/src/tools/claude-cli-tools.ts +++ b/ccw/src/tools/claude-cli-tools.ts @@ -42,6 +42,7 @@ export interface ClaudeCliToolsConfig { nativeResume: boolean; recursiveQuery: boolean; cache: ClaudeCacheSettings; + codeIndexMcp: 'codexlens' | 'ace'; // Code Index MCP provider }; } @@ -89,7 +90,8 @@ const DEFAULT_CONFIG: ClaudeCliToolsConfig = { injectionMode: 'auto', defaultPrefix: '', defaultSuffix: '' - } + }, + codeIndexMcp: 'codexlens' // Default to CodexLens } }; @@ -298,3 +300,76 @@ export function getClaudeCliToolsInfo(projectDir: string): { source: resolved.source }; } + +/** + * Update Code Index MCP provider and switch CLAUDE.md reference + */ +export function updateCodeIndexMcp( + projectDir: string, + provider: 'codexlens' | 'ace' +): { success: boolean; error?: string; config?: ClaudeCliToolsConfig } { + try { + // Update config + const config = loadClaudeCliTools(projectDir); + config.settings.codeIndexMcp = provider; + saveClaudeCliTools(projectDir, config); + + // Update CLAUDE.md reference + const claudeMdPath = path.join(projectDir, '.claude', 'CLAUDE.md'); + if (fs.existsSync(claudeMdPath)) { + let content = fs.readFileSync(claudeMdPath, 'utf-8'); + + // Define the file patterns + const codexlensPattern = /@~\/\.claude\/workflows\/context-tools\.md/g; + const acePattern = /@~\/\.claude\/workflows\/context-tools-ace\.md/g; + + // Also handle project-level references + const codexlensPatternProject = /@\.claude\/workflows\/context-tools\.md/g; + const acePatternProject = /@\.claude\/workflows\/context-tools-ace\.md/g; + + if (provider === 'ace') { + // Switch to ACE + content = content.replace(codexlensPattern, '@~/.claude/workflows/context-tools-ace.md'); + content = content.replace(codexlensPatternProject, '@.claude/workflows/context-tools-ace.md'); + } else { + // Switch to CodexLens + content = content.replace(acePattern, '@~/.claude/workflows/context-tools.md'); + content = content.replace(acePatternProject, '@.claude/workflows/context-tools.md'); + } + + fs.writeFileSync(claudeMdPath, content, 'utf-8'); + console.log(`[claude-cli-tools] Updated CLAUDE.md to use ${provider}`); + } + + // Also update global CLAUDE.md if it exists + const globalClaudeMdPath = path.join(os.homedir(), '.claude', 'CLAUDE.md'); + if (fs.existsSync(globalClaudeMdPath)) { + let content = fs.readFileSync(globalClaudeMdPath, 'utf-8'); + + const codexlensPattern = /@~\/\.claude\/workflows\/context-tools\.md/g; + const acePattern = /@~\/\.claude\/workflows\/context-tools-ace\.md/g; + + if (provider === 'ace') { + content = content.replace(codexlensPattern, '@~/.claude/workflows/context-tools-ace.md'); + } else { + content = content.replace(acePattern, '@~/.claude/workflows/context-tools.md'); + } + + fs.writeFileSync(globalClaudeMdPath, content, 'utf-8'); + console.log(`[claude-cli-tools] Updated global CLAUDE.md to use ${provider}`); + } + + return { success: true, config }; + } catch (err) { + console.error('[claude-cli-tools] Error updating Code Index MCP:', err); + return { success: false, error: (err as Error).message }; + } +} + +/** + * Get current Code Index MCP provider + */ +export function getCodeIndexMcp(projectDir: string): 'codexlens' | 'ace' { + const config = loadClaudeCliTools(projectDir); + return config.settings.codeIndexMcp || 'codexlens'; +} diff --git a/ccw/src/tools/cli-executor.ts b/ccw/src/tools/cli-executor.ts index ac48eb47..c8445103 100644 --- a/ccw/src/tools/cli-executor.ts +++ b/ccw/src/tools/cli-executor.ts @@ -337,9 +337,8 @@ function buildCommand(params: { args.push(nativeResume.sessionId); } // Codex resume still supports additional flags - if (dir) { - args.push('-C', dir); - } + // Note: -C is NOT used because spawn's cwd already sets the working directory + // Using both would cause path to be applied twice (e.g., codex-lens/codex-lens) // Permission configuration based on mode: // - analysis: --full-auto (read-only sandbox, no prompts) - safer for read operations // - write/auto: --dangerously-bypass-approvals-and-sandbox (full access for modifications) @@ -362,9 +361,8 @@ function buildCommand(params: { } else { // Standard exec mode args.push('exec'); - if (dir) { - args.push('-C', dir); - } + // Note: -C is NOT used because spawn's cwd already sets the working directory + // Using both would cause path to be applied twice (e.g., codex-lens/codex-lens) // Permission configuration based on mode: // - analysis: --full-auto (read-only sandbox, no prompts) - safer for read operations // - write/auto: --dangerously-bypass-approvals-and-sandbox (full access for modifications) diff --git a/codex-lens/src/codex_lens.egg-info/SOURCES.txt b/codex-lens/src/codex_lens.egg-info/SOURCES.txt index a14bfc8f..9f475809 100644 --- a/codex-lens/src/codex_lens.egg-info/SOURCES.txt +++ b/codex-lens/src/codex_lens.egg-info/SOURCES.txt @@ -29,10 +29,14 @@ src/codexlens/search/query_parser.py src/codexlens/search/ranking.py src/codexlens/semantic/__init__.py src/codexlens/semantic/ann_index.py +src/codexlens/semantic/base.py src/codexlens/semantic/chunker.py src/codexlens/semantic/code_extractor.py src/codexlens/semantic/embedder.py +src/codexlens/semantic/factory.py src/codexlens/semantic/gpu_support.py +src/codexlens/semantic/litellm_embedder.py +src/codexlens/semantic/rotational_embedder.py src/codexlens/semantic/vector_store.py src/codexlens/storage/__init__.py src/codexlens/storage/dir_index.py @@ -54,6 +58,7 @@ tests/test_cli_output.py tests/test_code_extractor.py tests/test_config.py tests/test_dual_fts.py +tests/test_embedding_backend_availability.py tests/test_encoding.py tests/test_enrichment.py tests/test_entities.py @@ -67,6 +72,7 @@ tests/test_parsers.py tests/test_performance_optimizations.py tests/test_pure_vector_search.py tests/test_query_parser.py +tests/test_recursive_splitting.py tests/test_result_grouping.py tests/test_rrf_fusion.py tests/test_schema_cleanup_migration.py