mirror of
https://github.com/catlog22/Claude-Code-Workflow.git
synced 2026-02-10 02:24:35 +08:00
feat(ccw): 添加 ccw tool exec 工具系统
新增工具:
- edit_file: AI辅助文件编辑 (update/line模式)
- get_modules_by_depth: 项目结构分析
- update_module_claude: CLAUDE.md文档生成
- generate_module_docs: 模块文档生成
- detect_changed_modules: Git变更检测
- classify_folders: 文件夹分类
- discover_design_files: 设计文件发现
- convert_tokens_to_css: 设计token转CSS
- ui_generate_preview: UI预览生成
- ui_instantiate_prototypes: 原型实例化
使用方式:
ccw tool list # 列出所有工具
ccw tool exec <name> '{}' # 执行工具
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,11 +1,18 @@
|
||||
// MCP Manager Component
|
||||
// Manages MCP server configuration from .claude.json
|
||||
// Manages MCP server configuration from multiple sources:
|
||||
// - Enterprise: managed-mcp.json (highest priority)
|
||||
// - User: ~/.claude.json mcpServers
|
||||
// - Project: .mcp.json in project root
|
||||
// - Local: ~/.claude.json projects[path].mcpServers
|
||||
|
||||
// ========== MCP State ==========
|
||||
let mcpConfig = null;
|
||||
let mcpAllProjects = {};
|
||||
let mcpGlobalServers = {};
|
||||
let mcpUserServers = {};
|
||||
let mcpEnterpriseServers = {};
|
||||
let mcpCurrentProjectServers = {};
|
||||
let mcpConfigSources = [];
|
||||
let mcpCreateMode = 'form'; // 'form' or 'json'
|
||||
|
||||
// ========== Initialization ==========
|
||||
@@ -33,6 +40,9 @@ async function loadMcpConfig() {
|
||||
mcpConfig = data;
|
||||
mcpAllProjects = data.projects || {};
|
||||
mcpGlobalServers = data.globalServers || {};
|
||||
mcpUserServers = data.userServers || {};
|
||||
mcpEnterpriseServers = data.enterpriseServers || {};
|
||||
mcpConfigSources = data.configSources || [];
|
||||
|
||||
// Get current project servers
|
||||
const currentPath = projectPath.replace(/\//g, '\\');
|
||||
|
||||
@@ -157,17 +157,19 @@ async function refreshWorkspace() {
|
||||
// Reload data from server
|
||||
const data = await loadDashboardData(projectPath);
|
||||
if (data) {
|
||||
// Update stores
|
||||
sessionDataStore = {};
|
||||
liteTaskDataStore = {};
|
||||
// Clear and repopulate stores
|
||||
Object.keys(sessionDataStore).forEach(k => delete sessionDataStore[k]);
|
||||
Object.keys(liteTaskDataStore).forEach(k => delete liteTaskDataStore[k]);
|
||||
|
||||
// Populate stores
|
||||
[...(data.activeSessions || []), ...(data.archivedSessions || [])].forEach(s => {
|
||||
sessionDataStore[s.session_id] = s;
|
||||
const sessionKey = `session-${s.session_id}`.replace(/[^a-zA-Z0-9-]/g, '-');
|
||||
sessionDataStore[sessionKey] = s;
|
||||
});
|
||||
|
||||
[...(data.liteTasks?.litePlan || []), ...(data.liteTasks?.liteFix || [])].forEach(s => {
|
||||
liteTaskDataStore[s.session_id] = s;
|
||||
const sessionKey = `lite-${s.session_id}`.replace(/[^a-zA-Z0-9-]/g, '-');
|
||||
liteTaskDataStore[sessionKey] = s;
|
||||
});
|
||||
|
||||
// Update global data
|
||||
|
||||
@@ -27,9 +27,11 @@ async function renderMcpManager() {
|
||||
// Separate current project servers and available servers
|
||||
const currentProjectServerNames = Object.keys(projectServers);
|
||||
|
||||
// Separate global servers and project servers that are not in current project
|
||||
const globalServerEntries = Object.entries(mcpGlobalServers)
|
||||
// Separate enterprise, user, and other project servers
|
||||
const enterpriseServerEntries = Object.entries(mcpEnterpriseServers || {})
|
||||
.filter(([name]) => !currentProjectServerNames.includes(name));
|
||||
const userServerEntries = Object.entries(mcpUserServers || {})
|
||||
.filter(([name]) => !currentProjectServerNames.includes(name) && !(mcpEnterpriseServers || {})[name]);
|
||||
const otherProjectServers = Object.entries(allAvailableServers)
|
||||
.filter(([name, info]) => !currentProjectServerNames.includes(name) && !info.isGlobal);
|
||||
|
||||
@@ -65,20 +67,40 @@ async function renderMcpManager() {
|
||||
`}
|
||||
</div>
|
||||
|
||||
<!-- Global MCP Servers -->
|
||||
${globalServerEntries.length > 0 ? `
|
||||
<!-- Enterprise MCP Servers (Managed) -->
|
||||
${enterpriseServerEntries.length > 0 ? `
|
||||
<div class="mcp-section mb-6">
|
||||
<div class="flex items-center justify-between mb-4">
|
||||
<div class="flex items-center gap-2">
|
||||
<span class="text-lg">🌐</span>
|
||||
<h3 class="text-lg font-semibold text-foreground">Global MCP Servers</h3>
|
||||
<span class="text-lg">🏢</span>
|
||||
<h3 class="text-lg font-semibold text-foreground">Enterprise MCP Servers</h3>
|
||||
<span class="text-xs px-2 py-0.5 bg-warning/20 text-warning rounded-full">Managed</span>
|
||||
</div>
|
||||
<span class="text-sm text-muted-foreground">${globalServerEntries.length} servers from ~/.claude/settings</span>
|
||||
<span class="text-sm text-muted-foreground">${enterpriseServerEntries.length} servers (read-only)</span>
|
||||
</div>
|
||||
|
||||
<div class="mcp-server-grid grid gap-3">
|
||||
${globalServerEntries.map(([serverName, serverConfig]) => {
|
||||
return renderGlobalServerCard(serverName, serverConfig);
|
||||
${enterpriseServerEntries.map(([serverName, serverConfig]) => {
|
||||
return renderEnterpriseServerCard(serverName, serverConfig);
|
||||
}).join('')}
|
||||
</div>
|
||||
</div>
|
||||
` : ''}
|
||||
|
||||
<!-- User MCP Servers -->
|
||||
${userServerEntries.length > 0 ? `
|
||||
<div class="mcp-section mb-6">
|
||||
<div class="flex items-center justify-between mb-4">
|
||||
<div class="flex items-center gap-2">
|
||||
<span class="text-lg">👤</span>
|
||||
<h3 class="text-lg font-semibold text-foreground">User MCP Servers</h3>
|
||||
</div>
|
||||
<span class="text-sm text-muted-foreground">${userServerEntries.length} servers from ~/.claude.json</span>
|
||||
</div>
|
||||
|
||||
<div class="mcp-server-grid grid gap-3">
|
||||
${userServerEntries.map(([serverName, serverConfig]) => {
|
||||
return renderGlobalServerCard(serverName, serverConfig, 'user');
|
||||
}).join('')}
|
||||
</div>
|
||||
</div>
|
||||
@@ -263,18 +285,19 @@ function renderAvailableServerCard(serverName, serverInfo) {
|
||||
`;
|
||||
}
|
||||
|
||||
function renderGlobalServerCard(serverName, serverConfig) {
|
||||
const command = serverConfig.command || 'N/A';
|
||||
function renderGlobalServerCard(serverName, serverConfig, source = 'user') {
|
||||
const command = serverConfig.command || serverConfig.url || 'N/A';
|
||||
const args = serverConfig.args || [];
|
||||
const hasEnv = serverConfig.env && Object.keys(serverConfig.env).length > 0;
|
||||
const serverType = serverConfig.type || 'stdio';
|
||||
|
||||
return `
|
||||
<div class="mcp-server-card mcp-server-global bg-card border border-primary/30 rounded-lg p-4 hover:shadow-md transition-all">
|
||||
<div class="flex items-start justify-between mb-3">
|
||||
<div class="flex items-center gap-2">
|
||||
<span class="text-xl">🌐</span>
|
||||
<span class="text-xl">👤</span>
|
||||
<h4 class="font-semibold text-foreground">${escapeHtml(serverName)}</h4>
|
||||
<span class="text-xs px-2 py-0.5 bg-primary/10 text-primary rounded-full">Global</span>
|
||||
<span class="text-xs px-2 py-0.5 bg-primary/10 text-primary rounded-full">User</span>
|
||||
</div>
|
||||
<button class="px-3 py-1 text-xs bg-primary text-primary-foreground rounded hover:opacity-90 transition-opacity"
|
||||
data-server-name="${escapeHtml(serverName)}"
|
||||
@@ -286,7 +309,7 @@ function renderGlobalServerCard(serverName, serverConfig) {
|
||||
|
||||
<div class="mcp-server-details text-sm space-y-1">
|
||||
<div class="flex items-center gap-2 text-muted-foreground">
|
||||
<span class="font-mono text-xs bg-muted px-1.5 py-0.5 rounded">cmd</span>
|
||||
<span class="font-mono text-xs bg-muted px-1.5 py-0.5 rounded">${serverType === 'stdio' ? 'cmd' : 'url'}</span>
|
||||
<span class="truncate" title="${escapeHtml(command)}">${escapeHtml(command)}</span>
|
||||
</div>
|
||||
${args.length > 0 ? `
|
||||
@@ -302,7 +325,52 @@ function renderGlobalServerCard(serverName, serverConfig) {
|
||||
</div>
|
||||
` : ''}
|
||||
<div class="flex items-center gap-2 text-muted-foreground mt-1">
|
||||
<span class="text-xs italic">Available to all projects from ~/.claude/settings</span>
|
||||
<span class="text-xs italic">Available to all projects from ~/.claude.json</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
function renderEnterpriseServerCard(serverName, serverConfig) {
|
||||
const command = serverConfig.command || serverConfig.url || 'N/A';
|
||||
const args = serverConfig.args || [];
|
||||
const hasEnv = serverConfig.env && Object.keys(serverConfig.env).length > 0;
|
||||
const serverType = serverConfig.type || 'stdio';
|
||||
|
||||
return `
|
||||
<div class="mcp-server-card mcp-server-enterprise bg-card border border-warning/30 rounded-lg p-4 hover:shadow-md transition-all">
|
||||
<div class="flex items-start justify-between mb-3">
|
||||
<div class="flex items-center gap-2">
|
||||
<span class="text-xl">🏢</span>
|
||||
<h4 class="font-semibold text-foreground">${escapeHtml(serverName)}</h4>
|
||||
<span class="text-xs px-2 py-0.5 bg-warning/20 text-warning rounded-full">Enterprise</span>
|
||||
<span class="text-xs text-muted-foreground">🔒</span>
|
||||
</div>
|
||||
<span class="px-3 py-1 text-xs bg-muted text-muted-foreground rounded cursor-not-allowed">
|
||||
Read-only
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="mcp-server-details text-sm space-y-1">
|
||||
<div class="flex items-center gap-2 text-muted-foreground">
|
||||
<span class="font-mono text-xs bg-muted px-1.5 py-0.5 rounded">${serverType === 'stdio' ? 'cmd' : 'url'}</span>
|
||||
<span class="truncate" title="${escapeHtml(command)}">${escapeHtml(command)}</span>
|
||||
</div>
|
||||
${args.length > 0 ? `
|
||||
<div class="flex items-start gap-2 text-muted-foreground">
|
||||
<span class="font-mono text-xs bg-muted px-1.5 py-0.5 rounded shrink-0">args</span>
|
||||
<span class="text-xs font-mono truncate" title="${escapeHtml(args.join(' '))}">${escapeHtml(args.slice(0, 3).join(' '))}${args.length > 3 ? '...' : ''}</span>
|
||||
</div>
|
||||
` : ''}
|
||||
${hasEnv ? `
|
||||
<div class="flex items-center gap-2 text-muted-foreground">
|
||||
<span class="font-mono text-xs bg-muted px-1.5 py-0.5 rounded">env</span>
|
||||
<span class="text-xs">${Object.keys(serverConfig.env).length} variables</span>
|
||||
</div>
|
||||
` : ''}
|
||||
<div class="flex items-center gap-2 text-muted-foreground mt-1">
|
||||
<span class="text-xs italic">Managed by organization (highest priority)</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user