Skip to content

Commit 2031004

Browse files
author
catlog22
committed
feat: 添加 Code Index MCP 提供者支持,更新相关 API 和配置
1 parent e8b9bca commit 2031004

File tree

7 files changed

+293
-13
lines changed

7 files changed

+293
-13
lines changed

.claude/commands/workflow/lite-plan.md

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -140,11 +140,17 @@ function selectAngles(taskDescription, count) {
140140

141141
const selectedAngles = selectAngles(task_description, complexity === 'High' ? 4 : (complexity === 'Medium' ? 3 : 1))
142142

143+
// Planning strategy determination
144+
const planningStrategy = complexity === 'Low'
145+
? 'Direct Claude Planning'
146+
: 'cli-lite-planning-agent'
147+
143148
console.log(`
144149
## Exploration Plan
145150
146151
Task Complexity: ${complexity}
147152
Selected Angles: ${selectedAngles.join(', ')}
153+
Planning Strategy: ${planningStrategy}
148154
149155
Launching ${selectedAngles.length} parallel explorations...
150156
`)
@@ -358,10 +364,7 @@ if (dedupedClarifications.length > 0) {
358364
```javascript
359365
// 分配规则(优先级从高到低):
360366
// 1. 用户明确指定:"用 gemini 分析..." → gemini, "codex 实现..." → codex
361-
// 2. 任务类型推断:
362-
// - 分析|审查|评估|探索 → gemini
363-
// - 实现|创建|修改|修复 → codex (复杂) 或 agent (简单)
364-
// 3. 默认 → agent
367+
// 2. 默认 → agent
365368

366369
const executorAssignments = {} // { taskId: { executor: 'gemini'|'codex'|'agent', reason: string } }
367370
plan.tasks.forEach(task => {
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
## MCP Tools Usage
2+
3+
### search_context (ACE) - Code Search (REQUIRED - HIGHEST PRIORITY)
4+
5+
**OVERRIDES**: All other search/discovery rules in other workflow files
6+
7+
**When**: ANY code discovery task, including:
8+
- Find code, understand codebase structure, locate implementations
9+
- Explore unknown locations
10+
- Verify file existence before reading
11+
- Pattern-based file discovery
12+
- Semantic code understanding
13+
14+
**Priority Rule**:
15+
1. **Always use mcp__ace-tool__search_context FIRST** for any code/file discovery
16+
2. Only use Built-in Grep for single-file exact line search (after location confirmed)
17+
3. Only use Built-in Read for known, confirmed file paths
18+
19+
**How**:
20+
```javascript
21+
// Natural language code search - best for understanding and exploration
22+
mcp__ace-tool__search_context({
23+
project_root_path: "/path/to/project",
24+
query: "authentication logic"
25+
})
26+
27+
// With keywords for better semantic matching
28+
mcp__ace-tool__search_context({
29+
project_root_path: "/path/to/project",
30+
query: "I want to find where the server handles user login. Keywords: auth, login, session"
31+
})
32+
```
33+
34+
**Good Query Examples**:
35+
- "Where is the function that handles user authentication?"
36+
- "What tests are there for the login functionality?"
37+
- "How is the database connected to the application?"
38+
- "I want to find where the server handles chunk merging. Keywords: upload chunk merge"
39+
- "Locate where the system refreshes cached data. Keywords: cache refresh, invalidation"
40+
41+
**Bad Query Examples** (use grep or file view instead):
42+
- "Find definition of constructor of class Foo" (use grep tool instead)
43+
- "Find all references to function bar" (use grep tool instead)
44+
- "Show me how Checkout class is used in services/payment.py" (use file view tool instead)
45+
46+
**Key Features**:
47+
- Real-time index of the codebase (always up-to-date)
48+
- Cross-language retrieval support
49+
- Semantic search with embeddings
50+
- No manual index initialization required
51+
52+
---
53+
54+
### read_file - Read File Contents
55+
56+
**When**: Read files found by search_context
57+
58+
**How**:
59+
```javascript
60+
read_file(path="/path/to/file.ts") // Single file
61+
read_file(path="/src/**/*.config.ts") // Pattern matching
62+
```
63+
64+
---
65+
66+
### edit_file - Modify Files
67+
68+
**When**: Built-in Edit tool fails or need advanced features
69+
70+
**How**:
71+
```javascript
72+
edit_file(path="/file.ts", old_string="...", new_string="...", mode="update")
73+
edit_file(path="/file.ts", line=10, content="...", mode="insert_after")
74+
```
75+
76+
**Modes**: `update` (replace text), `insert_after`, `insert_before`, `delete_line`
77+
78+
---
79+
80+
### write_file - Create/Overwrite Files
81+
82+
**When**: Create new files or completely replace content
83+
84+
**How**:
85+
```javascript
86+
write_file(path="/new-file.ts", content="...")
87+
```
88+
89+
---
90+
91+
### Exa - External Search
92+
93+
**When**: Find documentation/examples outside codebase
94+
95+
**How**:
96+
```javascript
97+
mcp__exa__search(query="React hooks 2025 documentation")
98+
mcp__exa__search(query="FastAPI auth example", numResults=10)
99+
mcp__exa__search(query="latest API docs", livecrawl="always")
100+
```
101+
102+
**Parameters**:
103+
- `query` (required): Search query string
104+
- `numResults` (optional): Number of results to return (default: 5)
105+
- `livecrawl` (optional): `"always"` or `"fallback"` for live crawling

ccw/src/core/routes/cli-routes.ts

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,9 @@ import {
4040
updateClaudeCacheSettings,
4141
getClaudeCliToolsInfo,
4242
addClaudeCustomEndpoint,
43-
removeClaudeCustomEndpoint
43+
removeClaudeCustomEndpoint,
44+
updateCodeIndexMcp,
45+
getCodeIndexMcp
4446
} from '../../tools/claude-cli-tools.js';
4547

4648
export interface RouteContext {
@@ -750,5 +752,45 @@ export async function handleCliRoutes(ctx: RouteContext): Promise<boolean> {
750752
return true;
751753
}
752754

755+
// API: Get Code Index MCP provider
756+
if (pathname === '/api/cli/code-index-mcp' && req.method === 'GET') {
757+
try {
758+
const provider = getCodeIndexMcp(initialPath);
759+
res.writeHead(200, { 'Content-Type': 'application/json' });
760+
res.end(JSON.stringify({ provider }));
761+
} catch (err) {
762+
res.writeHead(500, { 'Content-Type': 'application/json' });
763+
res.end(JSON.stringify({ error: (err as Error).message }));
764+
}
765+
return true;
766+
}
767+
768+
// API: Update Code Index MCP provider
769+
if (pathname === '/api/cli/code-index-mcp' && req.method === 'PUT') {
770+
handlePostRequest(req, res, async (body: unknown) => {
771+
try {
772+
const { provider } = body as { provider: 'codexlens' | 'ace' };
773+
if (!provider || !['codexlens', 'ace'].includes(provider)) {
774+
return { error: 'Invalid provider. Must be "codexlens" or "ace"', status: 400 };
775+
}
776+
777+
const result = updateCodeIndexMcp(initialPath, provider);
778+
779+
if (result.success) {
780+
broadcastToClients({
781+
type: 'CODE_INDEX_MCP_UPDATED',
782+
payload: { provider, timestamp: new Date().toISOString() }
783+
});
784+
return { success: true, provider };
785+
} else {
786+
return { error: result.error, status: 500 };
787+
}
788+
} catch (err) {
789+
return { error: (err as Error).message, status: 500 };
790+
}
791+
});
792+
return true;
793+
}
794+
753795
return false;
754796
}

ccw/src/templates/dashboard-js/components/cli-status.js

Lines changed: 52 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@ let nativeResumeEnabled = localStorage.getItem('ccw-native-resume') !== 'false';
2121
// Recursive Query settings (for hierarchical storage aggregation)
2222
let recursiveQueryEnabled = localStorage.getItem('ccw-recursive-query') !== 'false'; // default true
2323

24+
// Code Index MCP provider (codexlens or ace)
25+
let codeIndexMcpProvider = 'codexlens';
26+
2427
// ========== Initialization ==========
2528
function initCliStatus() {
2629
// Load all statuses in one call using aggregated endpoint
@@ -241,7 +244,12 @@ async function loadCliToolsConfig() {
241244
defaultCliTool = data.defaultTool;
242245
}
243246

244-
console.log('[CLI Config] Loaded from:', data._configInfo?.source || 'unknown', '| Default:', data.defaultTool);
247+
// Load Code Index MCP provider from config
248+
if (data.settings?.codeIndexMcp) {
249+
codeIndexMcpProvider = data.settings.codeIndexMcp;
250+
}
251+
252+
console.log('[CLI Config] Loaded from:', data._configInfo?.source || 'unknown', '| Default:', data.defaultTool, '| CodeIndexMCP:', codeIndexMcpProvider);
245253
return data;
246254
} catch (err) {
247255
console.error('Failed to load CLI tools config:', err);
@@ -614,6 +622,25 @@ function renderCliStatus() {
614622
</div>
615623
<p class="cli-setting-desc">Cache prefix/suffix injection mode for prompts</p>
616624
</div>
625+
<div class="cli-setting-item">
626+
<label class="cli-setting-label">
627+
<i data-lucide="search" class="w-3 h-3"></i>
628+
Code Index MCP
629+
</label>
630+
<div class="cli-setting-control">
631+
<div class="flex items-center bg-muted rounded-lg p-0.5">
632+
<button class="code-mcp-btn px-3 py-1.5 text-xs font-medium rounded-md transition-all ${codeIndexMcpProvider === 'codexlens' ? 'bg-primary text-primary-foreground shadow-sm' : 'text-muted-foreground hover:text-foreground'}"
633+
onclick="setCodeIndexMcpProvider('codexlens')">
634+
CodexLens
635+
</button>
636+
<button class="code-mcp-btn px-3 py-1.5 text-xs font-medium rounded-md transition-all ${codeIndexMcpProvider === 'ace' ? 'bg-primary text-primary-foreground shadow-sm' : 'text-muted-foreground hover:text-foreground'}"
637+
onclick="setCodeIndexMcpProvider('ace')">
638+
ACE
639+
</button>
640+
</div>
641+
</div>
642+
<p class="cli-setting-desc">Code search provider (updates CLAUDE.md context-tools reference)</p>
643+
</div>
617644
</div>
618645
</div>
619646
`;
@@ -736,6 +763,30 @@ async function setCacheInjectionMode(mode) {
736763
}
737764
}
738765

766+
async function setCodeIndexMcpProvider(provider) {
767+
try {
768+
const response = await fetch('/api/cli/code-index-mcp', {
769+
method: 'PUT',
770+
headers: { 'Content-Type': 'application/json' },
771+
body: JSON.stringify({ provider: provider })
772+
});
773+
if (response.ok) {
774+
codeIndexMcpProvider = provider;
775+
if (window.claudeCliToolsConfig && window.claudeCliToolsConfig.settings) {
776+
window.claudeCliToolsConfig.settings.codeIndexMcp = provider;
777+
}
778+
showRefreshToast(`Code Index MCP switched to ${provider === 'ace' ? 'ACE (Augment)' : 'CodexLens'}`, 'success');
779+
renderCliStatus();
780+
} else {
781+
const data = await response.json();
782+
showRefreshToast(`Failed to switch Code Index MCP: ${data.error}`, 'error');
783+
}
784+
} catch (err) {
785+
console.error('Failed to switch Code Index MCP:', err);
786+
showRefreshToast('Failed to switch Code Index MCP', 'error');
787+
}
788+
}
789+
739790
async function refreshAllCliStatus() {
740791
await loadAllStatuses();
741792
renderCliStatus();

ccw/src/tools/claude-cli-tools.ts

Lines changed: 76 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ export interface ClaudeCliToolsConfig {
4242
nativeResume: boolean;
4343
recursiveQuery: boolean;
4444
cache: ClaudeCacheSettings;
45+
codeIndexMcp: 'codexlens' | 'ace'; // Code Index MCP provider
4546
};
4647
}
4748

@@ -89,7 +90,8 @@ const DEFAULT_CONFIG: ClaudeCliToolsConfig = {
8990
injectionMode: 'auto',
9091
defaultPrefix: '',
9192
defaultSuffix: ''
92-
}
93+
},
94+
codeIndexMcp: 'codexlens' // Default to CodexLens
9395
}
9496
};
9597

@@ -298,3 +300,76 @@ export function getClaudeCliToolsInfo(projectDir: string): {
298300
source: resolved.source
299301
};
300302
}
303+
304+
/**
305+
* Update Code Index MCP provider and switch CLAUDE.md reference
306+
*/
307+
export function updateCodeIndexMcp(
308+
projectDir: string,
309+
provider: 'codexlens' | 'ace'
310+
): { success: boolean; error?: string; config?: ClaudeCliToolsConfig } {
311+
try {
312+
// Update config
313+
const config = loadClaudeCliTools(projectDir);
314+
config.settings.codeIndexMcp = provider;
315+
saveClaudeCliTools(projectDir, config);
316+
317+
// Update CLAUDE.md reference
318+
const claudeMdPath = path.join(projectDir, '.claude', 'CLAUDE.md');
319+
if (fs.existsSync(claudeMdPath)) {
320+
let content = fs.readFileSync(claudeMdPath, 'utf-8');
321+
322+
// Define the file patterns
323+
const codexlensPattern = /@~\/\.claude\/workflows\/context-tools\.md/g;
324+
const acePattern = /@~\/\.claude\/workflows\/context-tools-ace\.md/g;
325+
326+
// Also handle project-level references
327+
const codexlensPatternProject = /@\.claude\/workflows\/context-tools\.md/g;
328+
const acePatternProject = /@\.claude\/workflows\/context-tools-ace\.md/g;
329+
330+
if (provider === 'ace') {
331+
// Switch to ACE
332+
content = content.replace(codexlensPattern, '@~/.claude/workflows/context-tools-ace.md');
333+
content = content.replace(codexlensPatternProject, '@.claude/workflows/context-tools-ace.md');
334+
} else {
335+
// Switch to CodexLens
336+
content = content.replace(acePattern, '@~/.claude/workflows/context-tools.md');
337+
content = content.replace(acePatternProject, '@.claude/workflows/context-tools.md');
338+
}
339+
340+
fs.writeFileSync(claudeMdPath, content, 'utf-8');
341+
console.log(`[claude-cli-tools] Updated CLAUDE.md to use ${provider}`);
342+
}
343+
344+
// Also update global CLAUDE.md if it exists
345+
const globalClaudeMdPath = path.join(os.homedir(), '.claude', 'CLAUDE.md');
346+
if (fs.existsSync(globalClaudeMdPath)) {
347+
let content = fs.readFileSync(globalClaudeMdPath, 'utf-8');
348+
349+
const codexlensPattern = /@~\/\.claude\/workflows\/context-tools\.md/g;
350+
const acePattern = /@~\/\.claude\/workflows\/context-tools-ace\.md/g;
351+
352+
if (provider === 'ace') {
353+
content = content.replace(codexlensPattern, '@~/.claude/workflows/context-tools-ace.md');
354+
} else {
355+
content = content.replace(acePattern, '@~/.claude/workflows/context-tools.md');
356+
}
357+
358+
fs.writeFileSync(globalClaudeMdPath, content, 'utf-8');
359+
console.log(`[claude-cli-tools] Updated global CLAUDE.md to use ${provider}`);
360+
}
361+
362+
return { success: true, config };
363+
} catch (err) {
364+
console.error('[claude-cli-tools] Error updating Code Index MCP:', err);
365+
return { success: false, error: (err as Error).message };
366+
}
367+
}
368+
369+
/**
370+
* Get current Code Index MCP provider
371+
*/
372+
export function getCodeIndexMcp(projectDir: string): 'codexlens' | 'ace' {
373+
const config = loadClaudeCliTools(projectDir);
374+
return config.settings.codeIndexMcp || 'codexlens';
375+
}

ccw/src/tools/cli-executor.ts

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -337,9 +337,8 @@ function buildCommand(params: {
337337
args.push(nativeResume.sessionId);
338338
}
339339
// Codex resume still supports additional flags
340-
if (dir) {
341-
args.push('-C', dir);
342-
}
340+
// Note: -C is NOT used because spawn's cwd already sets the working directory
341+
// Using both would cause path to be applied twice (e.g., codex-lens/codex-lens)
343342
// Permission configuration based on mode:
344343
// - analysis: --full-auto (read-only sandbox, no prompts) - safer for read operations
345344
// - write/auto: --dangerously-bypass-approvals-and-sandbox (full access for modifications)
@@ -362,9 +361,8 @@ function buildCommand(params: {
362361
} else {
363362
// Standard exec mode
364363
args.push('exec');
365-
if (dir) {
366-
args.push('-C', dir);
367-
}
364+
// Note: -C is NOT used because spawn's cwd already sets the working directory
365+
// Using both would cause path to be applied twice (e.g., codex-lens/codex-lens)
368366
// Permission configuration based on mode:
369367
// - analysis: --full-auto (read-only sandbox, no prompts) - safer for read operations
370368
// - write/auto: --dangerously-bypass-approvals-and-sandbox (full access for modifications)

0 commit comments

Comments
 (0)