claude-code-workflow 6.3.48 → 6.3.49
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/CLAUDE.md +6 -8
- package/.claude/agents/action-planning-agent.md +28 -45
- package/.claude/agents/cli-lite-planning-agent.md +93 -1
- package/.claude/agents/code-developer.md +144 -27
- package/.claude/commands/ccw-coordinator.md +175 -21
- package/.claude/commands/ccw-debug.md +832 -0
- package/.claude/commands/ccw.md +90 -9
- package/.claude/commands/cli/cli-init.md +1 -0
- package/.claude/commands/issue/convert-to-plan.md +718 -0
- package/.claude/commands/issue/from-brainstorm.md +382 -0
- package/.claude/commands/memory/tips.md +332 -0
- package/.claude/commands/workflow/analyze-with-file.md +804 -0
- package/.claude/commands/workflow/brainstorm/auto-parallel.md +18 -43
- package/.claude/commands/workflow/brainstorm/role-analysis.md +705 -0
- package/.claude/commands/workflow/brainstorm-with-file.md +1153 -0
- package/.claude/commands/workflow/debug-with-file.md +7 -5
- package/.claude/commands/workflow/execute.md +6 -4
- package/.claude/commands/workflow/lite-plan.md +2 -2
- package/.claude/commands/workflow/plan-verify.md +162 -327
- package/.claude/commands/workflow/plan.md +162 -26
- package/.claude/commands/workflow/replan.md +78 -2
- package/.claude/commands/workflow/{review-fix.md → review-cycle-fix.md} +6 -6
- package/.claude/commands/workflow/review-module-cycle.md +2 -2
- package/.claude/commands/workflow/review-session-cycle.md +2 -2
- package/.claude/commands/workflow/tools/conflict-resolution.md +16 -26
- package/.claude/commands/workflow/tools/context-gather.md +81 -118
- package/.claude/commands/workflow/tools/task-generate-agent.md +94 -10
- package/.claude/skills/ccw-help/command.json +4 -4
- package/.claude/skills/lite-skill-generator/SKILL.md +650 -0
- package/.claude/skills/lite-skill-generator/templates/simple-skill.md +68 -0
- package/.claude/skills/lite-skill-generator/templates/style-guide.md +64 -0
- package/.claude/skills/skill-generator/SKILL.md +277 -85
- package/.claude/skills/skill-generator/phases/01-requirements-discovery.md +4 -15
- package/.claude/skills/skill-generator/phases/02-structure-generation.md +72 -17
- package/.claude/skills/skill-generator/phases/03-phase-generation.md +218 -51
- package/.claude/skills/skill-generator/phases/04-specs-templates.md +111 -41
- package/.claude/skills/skill-generator/phases/05-validation.md +139 -56
- package/.claude/skills/skill-generator/templates/autonomous-action.md +78 -268
- package/.claude/skills/skill-generator/templates/autonomous-orchestrator.md +14 -0
- package/.claude/skills/skill-generator/templates/code-analysis-action.md +12 -0
- package/.claude/skills/skill-generator/templates/llm-action.md +12 -0
- package/.claude/skills/skill-generator/templates/script-template.md +368 -0
- package/.claude/skills/skill-generator/templates/sequential-phase.md +14 -0
- package/.claude/skills/skill-generator/templates/skill-md.md +14 -0
- package/.claude/skills/skill-tuning/SKILL.md +130 -266
- package/.claude/skills/skill-tuning/phases/orchestrator.md +95 -283
- package/.claude/skills/skill-tuning/specs/problem-taxonomy.md +90 -198
- package/.claude/skills/skill-tuning/specs/tuning-strategies.md +193 -1345
- package/.claude/workflows/cli-templates/schemas/plan-verify-agent-schema.json +47 -0
- package/.claude/workflows/cli-templates/schemas/verify-json-schema.json +158 -0
- package/.claude/workflows/cli-tools-usage.md +1 -1
- package/.codex/AGENTS.md +1 -3
- package/.codex/prompts/analyze-with-file.md +607 -0
- package/.codex/prompts/brainstorm-to-cycle.md +455 -0
- package/.codex/prompts/brainstorm-with-file.md +933 -0
- package/.codex/prompts/debug-with-file.md +15 -20
- package/.codex/skills/ccw-cli-tools/SKILL.md +559 -0
- package/ccw/dist/commands/cli.d.ts.map +1 -1
- package/ccw/dist/commands/cli.js +29 -5
- package/ccw/dist/commands/cli.js.map +1 -1
- package/ccw/dist/commands/issue.d.ts +2 -0
- package/ccw/dist/commands/issue.d.ts.map +1 -1
- package/ccw/dist/commands/issue.js +62 -20
- package/ccw/dist/commands/issue.js.map +1 -1
- package/ccw/dist/config/litellm-api-config-manager.d.ts.map +1 -1
- package/ccw/dist/config/litellm-api-config-manager.js +5 -3
- package/ccw/dist/config/litellm-api-config-manager.js.map +1 -1
- package/ccw/dist/config/litellm-provider-models.d.ts +73 -0
- package/ccw/dist/config/litellm-provider-models.d.ts.map +1 -0
- package/ccw/dist/config/litellm-provider-models.js +172 -0
- package/ccw/dist/config/litellm-provider-models.js.map +1 -0
- package/ccw/dist/config/provider-models.d.ts +25 -51
- package/ccw/dist/config/provider-models.d.ts.map +1 -1
- package/ccw/dist/config/provider-models.js +84 -149
- package/ccw/dist/config/provider-models.js.map +1 -1
- package/ccw/dist/config/storage-paths.d.ts.map +1 -1
- package/ccw/dist/config/storage-paths.js +23 -5
- package/ccw/dist/config/storage-paths.js.map +1 -1
- package/ccw/dist/core/auth/csrf-middleware.js +3 -3
- package/ccw/dist/core/auth/csrf-middleware.js.map +1 -1
- package/ccw/dist/core/dashboard-generator.d.ts.map +1 -1
- package/ccw/dist/core/dashboard-generator.js +3 -1
- package/ccw/dist/core/dashboard-generator.js.map +1 -1
- package/ccw/dist/core/routes/claude-routes.d.ts.map +1 -1
- package/ccw/dist/core/routes/claude-routes.js +206 -14
- package/ccw/dist/core/routes/claude-routes.js.map +1 -1
- package/ccw/dist/core/routes/cli-routes.d.ts.map +1 -1
- package/ccw/dist/core/routes/cli-routes.js.map +1 -1
- package/ccw/dist/core/routes/commands-routes.d.ts +7 -0
- package/ccw/dist/core/routes/commands-routes.d.ts.map +1 -0
- package/ccw/dist/core/routes/commands-routes.js +480 -0
- package/ccw/dist/core/routes/commands-routes.js.map +1 -0
- package/ccw/dist/core/routes/model-routes.d.ts +11 -0
- package/ccw/dist/core/routes/model-routes.d.ts.map +1 -0
- package/ccw/dist/core/routes/model-routes.js +112 -0
- package/ccw/dist/core/routes/model-routes.js.map +1 -0
- package/ccw/dist/core/routes/nav-status-routes.d.ts.map +1 -1
- package/ccw/dist/core/routes/nav-status-routes.js +84 -1
- package/ccw/dist/core/routes/nav-status-routes.js.map +1 -1
- package/ccw/dist/core/routes/provider-routes.d.ts +11 -0
- package/ccw/dist/core/routes/provider-routes.d.ts.map +1 -0
- package/ccw/dist/core/routes/provider-routes.js +67 -0
- package/ccw/dist/core/routes/provider-routes.js.map +1 -0
- package/ccw/dist/core/routes/skills-routes.d.ts.map +1 -1
- package/ccw/dist/core/routes/skills-routes.js +219 -7
- package/ccw/dist/core/routes/skills-routes.js.map +1 -1
- package/ccw/dist/core/routes/system-routes.d.ts.map +1 -1
- package/ccw/dist/core/routes/system-routes.js +58 -6
- package/ccw/dist/core/routes/system-routes.js.map +1 -1
- package/ccw/dist/core/server.d.ts.map +1 -1
- package/ccw/dist/core/server.js +13 -0
- package/ccw/dist/core/server.js.map +1 -1
- package/ccw/dist/mcp-server/index.js +2 -2
- package/ccw/dist/mcp-server/index.js.map +1 -1
- package/ccw/dist/tools/claude-cli-tools.d.ts +48 -11
- package/ccw/dist/tools/claude-cli-tools.d.ts.map +1 -1
- package/ccw/dist/tools/claude-cli-tools.js +146 -50
- package/ccw/dist/tools/claude-cli-tools.js.map +1 -1
- package/ccw/dist/tools/cli-config-manager.d.ts +1 -13
- package/ccw/dist/tools/cli-config-manager.d.ts.map +1 -1
- package/ccw/dist/tools/cli-config-manager.js +3 -27
- package/ccw/dist/tools/cli-config-manager.js.map +1 -1
- package/ccw/dist/tools/cli-executor-core.d.ts.map +1 -1
- package/ccw/dist/tools/cli-executor-core.js +7 -2
- package/ccw/dist/tools/cli-executor-core.js.map +1 -1
- package/ccw/dist/tools/cli-executor-state.d.ts.map +1 -1
- package/ccw/dist/tools/cli-history-store.d.ts +11 -0
- package/ccw/dist/tools/cli-history-store.d.ts.map +1 -1
- package/ccw/dist/tools/cli-history-store.js +82 -2
- package/ccw/dist/tools/cli-history-store.js.map +1 -1
- package/ccw/dist/tools/command-registry.d.ts +7 -0
- package/ccw/dist/tools/command-registry.d.ts.map +1 -1
- package/ccw/dist/tools/command-registry.js +14 -1
- package/ccw/dist/tools/command-registry.js.map +1 -1
- package/ccw/dist/tools/generate-module-docs.d.ts.map +1 -1
- package/ccw/dist/tools/generate-module-docs.js +11 -7
- package/ccw/dist/tools/generate-module-docs.js.map +1 -1
- package/ccw/dist/tools/litellm-executor.d.ts +1 -0
- package/ccw/dist/tools/litellm-executor.d.ts.map +1 -1
- package/ccw/dist/tools/litellm-executor.js +11 -9
- package/ccw/dist/tools/litellm-executor.js.map +1 -1
- package/ccw/dist/types/skill-types.d.ts +97 -0
- package/ccw/dist/types/skill-types.d.ts.map +1 -0
- package/ccw/dist/types/skill-types.js +6 -0
- package/ccw/dist/types/skill-types.js.map +1 -0
- package/ccw/src/commands/cli.ts +36 -5
- package/ccw/src/commands/issue.ts +81 -26
- package/ccw/src/config/litellm-api-config-manager.ts +5 -3
- package/ccw/src/config/litellm-provider-models.ts +222 -0
- package/ccw/src/config/provider-models.ts +91 -190
- package/ccw/src/config/storage-paths.ts +20 -5
- package/ccw/src/core/auth/csrf-middleware.ts +3 -3
- package/ccw/src/core/dashboard-generator.ts +3 -1
- package/ccw/src/core/routes/claude-routes.ts +233 -15
- package/ccw/src/core/routes/cli-routes.ts +2 -3
- package/ccw/src/core/routes/commands-routes.ts +620 -0
- package/ccw/src/core/routes/nav-status-routes.ts +95 -1
- package/ccw/src/core/routes/provider-routes.ts +78 -0
- package/ccw/src/core/routes/skills-routes.ts +266 -45
- package/ccw/src/core/routes/system-routes.ts +102 -50
- package/ccw/src/core/server.ts +13 -0
- package/ccw/src/mcp-server/index.ts +2 -2
- package/ccw/src/templates/dashboard-css/18-cli-settings.css +35 -0
- package/ccw/src/templates/dashboard-css/37-commands.css +193 -0
- package/ccw/src/templates/dashboard-js/components/navigation.js +4 -0
- package/ccw/src/templates/dashboard-js/i18n.js +116 -0
- package/ccw/src/templates/dashboard-js/views/cli-manager.js +249 -4
- package/ccw/src/templates/dashboard-js/views/commands-manager.js +503 -0
- package/ccw/src/templates/dashboard-js/views/issue-manager.js +7 -7
- package/ccw/src/templates/dashboard-js/views/mcp-manager.js +2 -7
- package/ccw/src/templates/dashboard-js/views/skills-manager.js +164 -23
- package/ccw/src/templates/dashboard.html +7 -0
- package/ccw/src/tools/claude-cli-tools.ts +170 -56
- package/ccw/src/tools/cli-config-manager.ts +2 -33
- package/ccw/src/tools/cli-executor-core.ts +8 -2
- package/ccw/src/tools/cli-history-store.ts +92 -2
- package/ccw/src/tools/command-registry.ts +16 -1
- package/ccw/src/tools/generate-module-docs.ts +11 -7
- package/ccw/src/tools/litellm-executor.ts +13 -9
- package/ccw/src/types/skill-types.ts +99 -0
- package/package.json +1 -1
- package/.claude/commands/enhance-prompt.md +0 -93
- package/.claude/commands/memory/code-map-memory.md +0 -687
- package/.claude/commands/memory/docs.md +0 -615
- package/.claude/commands/memory/load-skill-memory.md +0 -182
- package/.claude/commands/memory/skill-memory.md +0 -525
- package/.claude/commands/memory/swagger-docs.md +0 -773
- package/.claude/commands/memory/tech-research-rules.md +0 -310
- package/.claude/commands/memory/workflow-skill-memory.md +0 -517
- package/.claude/commands/task/breakdown.md +0 -208
- package/.claude/commands/task/create.md +0 -152
- package/.claude/commands/task/execute.md +0 -270
- package/.claude/commands/task/replan.md +0 -441
- package/.claude/commands/version.md +0 -254
- package/.claude/commands/workflow/action-plan-verify.md +0 -485
- package/.claude/commands/workflow/brainstorm/api-designer.md +0 -587
- package/.claude/commands/workflow/brainstorm/data-architect.md +0 -220
- package/.claude/commands/workflow/brainstorm/product-manager.md +0 -200
- package/.claude/commands/workflow/brainstorm/product-owner.md +0 -200
- package/.claude/commands/workflow/brainstorm/scrum-master.md +0 -200
- package/.claude/commands/workflow/brainstorm/subject-matter-expert.md +0 -200
- package/.claude/commands/workflow/brainstorm/system-architect.md +0 -389
- package/.claude/commands/workflow/brainstorm/ui-designer.md +0 -221
- package/.claude/commands/workflow/brainstorm/ux-expert.md +0 -221
- package/.claude/commands/workflow/debug.md +0 -331
- package/.claude/commands/workflow/develop-with-file.md +0 -1044
- package/.claude/skills/ccw-loop/README.md +0 -303
- package/.claude/skills/skill-generator/templates/script-bash.md +0 -277
- package/.claude/skills/skill-generator/templates/script-python.md +0 -198
- package/.codex/prompts/debug.md +0 -318
- package/ccw/src/core/routes/mcp-routes.ts.backup +0 -549
|
@@ -1,549 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* MCP Routes Module
|
|
3
|
-
* Handles all MCP-related API endpoints
|
|
4
|
-
*/
|
|
5
|
-
import type { IncomingMessage, ServerResponse } from 'http';
|
|
6
|
-
import { readFileSync, writeFileSync, existsSync, mkdirSync } from 'fs';
|
|
7
|
-
import { join, dirname } from 'path';
|
|
8
|
-
import { homedir } from 'os';
|
|
9
|
-
|
|
10
|
-
// Claude config file path
|
|
11
|
-
const CLAUDE_CONFIG_PATH = join(homedir(), '.claude.json');
|
|
12
|
-
|
|
13
|
-
export interface RouteContext {
|
|
14
|
-
pathname: string;
|
|
15
|
-
url: URL;
|
|
16
|
-
req: IncomingMessage;
|
|
17
|
-
res: ServerResponse;
|
|
18
|
-
initialPath: string;
|
|
19
|
-
handlePostRequest: (req: IncomingMessage, res: ServerResponse, handler: (body: unknown) => Promise<any>) => void;
|
|
20
|
-
broadcastToClients: (data: unknown) => void;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
// ========================================
|
|
24
|
-
// Helper Functions
|
|
25
|
-
// ========================================
|
|
26
|
-
|
|
27
|
-
/**
|
|
28
|
-
* Get enterprise managed MCP path (platform-specific)
|
|
29
|
-
*/
|
|
30
|
-
function getEnterpriseMcpPath(): string {
|
|
31
|
-
const platform = process.platform;
|
|
32
|
-
if (platform === 'darwin') {
|
|
33
|
-
return '/Library/Application Support/ClaudeCode/managed-mcp.json';
|
|
34
|
-
} else if (platform === 'win32') {
|
|
35
|
-
return 'C:\\Program Files\\ClaudeCode\\managed-mcp.json';
|
|
36
|
-
} else {
|
|
37
|
-
// Linux and WSL
|
|
38
|
-
return '/etc/claude-code/managed-mcp.json';
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
/**
|
|
43
|
-
* Safely read and parse JSON file
|
|
44
|
-
*/
|
|
45
|
-
function safeReadJson(filePath) {
|
|
46
|
-
try {
|
|
47
|
-
if (!existsSync(filePath)) return null;
|
|
48
|
-
const content = readFileSync(filePath, 'utf8');
|
|
49
|
-
return JSON.parse(content);
|
|
50
|
-
} catch {
|
|
51
|
-
return null;
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
/**
|
|
56
|
-
* Get MCP servers from a JSON file (expects mcpServers key at top level)
|
|
57
|
-
* @param {string} filePath
|
|
58
|
-
* @returns {Object} mcpServers object or empty object
|
|
59
|
-
*/
|
|
60
|
-
function getMcpServersFromFile(filePath) {
|
|
61
|
-
const config = safeReadJson(filePath);
|
|
62
|
-
if (!config) return {};
|
|
63
|
-
return config.mcpServers || {};
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
/**
|
|
67
|
-
* Get MCP configuration from multiple sources (per official Claude Code docs):
|
|
68
|
-
*
|
|
69
|
-
* Priority (highest to lowest):
|
|
70
|
-
* 1. Enterprise managed-mcp.json (cannot be overridden)
|
|
71
|
-
* 2. Local scope (project-specific private in ~/.claude.json)
|
|
72
|
-
* 3. Project scope (.mcp.json in project root)
|
|
73
|
-
* 4. User scope (mcpServers in ~/.claude.json)
|
|
74
|
-
*
|
|
75
|
-
* Note: ~/.claude/settings.json is for MCP PERMISSIONS, NOT definitions!
|
|
76
|
-
*
|
|
77
|
-
* @returns {Object}
|
|
78
|
-
*/
|
|
79
|
-
function getMcpConfig() {
|
|
80
|
-
try {
|
|
81
|
-
const result = {
|
|
82
|
-
projects: {},
|
|
83
|
-
userServers: {}, // User-level servers from ~/.claude.json mcpServers
|
|
84
|
-
enterpriseServers: {}, // Enterprise managed servers (highest priority)
|
|
85
|
-
configSources: [] // Track where configs came from for debugging
|
|
86
|
-
};
|
|
87
|
-
|
|
88
|
-
// 1. Read Enterprise managed MCP servers (highest priority)
|
|
89
|
-
const enterprisePath = getEnterpriseMcpPath();
|
|
90
|
-
if (existsSync(enterprisePath)) {
|
|
91
|
-
const enterpriseConfig = safeReadJson(enterprisePath);
|
|
92
|
-
if (enterpriseConfig?.mcpServers) {
|
|
93
|
-
result.enterpriseServers = enterpriseConfig.mcpServers;
|
|
94
|
-
result.configSources.push({ type: 'enterprise', path: enterprisePath, count: Object.keys(enterpriseConfig.mcpServers).length });
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
// 2. Read from ~/.claude.json
|
|
99
|
-
if (existsSync(CLAUDE_CONFIG_PATH)) {
|
|
100
|
-
const claudeConfig = safeReadJson(CLAUDE_CONFIG_PATH);
|
|
101
|
-
if (claudeConfig) {
|
|
102
|
-
// 2a. User-level mcpServers (top-level mcpServers key)
|
|
103
|
-
if (claudeConfig.mcpServers) {
|
|
104
|
-
result.userServers = claudeConfig.mcpServers;
|
|
105
|
-
result.configSources.push({ type: 'user', path: CLAUDE_CONFIG_PATH, count: Object.keys(claudeConfig.mcpServers).length });
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
// 2b. Project-specific configurations (projects[path].mcpServers)
|
|
109
|
-
if (claudeConfig.projects) {
|
|
110
|
-
result.projects = claudeConfig.projects;
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
// 3. For each known project, check for .mcp.json (project-level config)
|
|
116
|
-
const projectPaths = Object.keys(result.projects);
|
|
117
|
-
for (const projectPath of projectPaths) {
|
|
118
|
-
const mcpJsonPath = join(projectPath, '.mcp.json');
|
|
119
|
-
if (existsSync(mcpJsonPath)) {
|
|
120
|
-
const mcpJsonConfig = safeReadJson(mcpJsonPath);
|
|
121
|
-
if (mcpJsonConfig?.mcpServers) {
|
|
122
|
-
// Merge .mcp.json servers into project config
|
|
123
|
-
// Project's .mcp.json has lower priority than ~/.claude.json projects[path].mcpServers
|
|
124
|
-
const existingServers = result.projects[projectPath]?.mcpServers || {};
|
|
125
|
-
result.projects[projectPath] = {
|
|
126
|
-
...result.projects[projectPath],
|
|
127
|
-
mcpServers: {
|
|
128
|
-
...mcpJsonConfig.mcpServers, // .mcp.json (lower priority)
|
|
129
|
-
...existingServers // ~/.claude.json projects[path] (higher priority)
|
|
130
|
-
},
|
|
131
|
-
mcpJsonPath: mcpJsonPath // Track source for debugging
|
|
132
|
-
};
|
|
133
|
-
result.configSources.push({ type: 'project-mcp-json', path: mcpJsonPath, count: Object.keys(mcpJsonConfig.mcpServers).length });
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
// Build globalServers by merging user and enterprise servers
|
|
139
|
-
// Enterprise servers override user servers
|
|
140
|
-
result.globalServers = {
|
|
141
|
-
...result.userServers,
|
|
142
|
-
...result.enterpriseServers
|
|
143
|
-
};
|
|
144
|
-
|
|
145
|
-
return result;
|
|
146
|
-
} catch (error: unknown) {
|
|
147
|
-
console.error('Error reading MCP config:', error);
|
|
148
|
-
return { projects: {}, globalServers: {}, userServers: {}, enterpriseServers: {}, configSources: [], error: (error as Error).message };
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
/**
|
|
153
|
-
* Normalize project path for .claude.json (Windows backslash format)
|
|
154
|
-
* @param {string} path
|
|
155
|
-
* @returns {string}
|
|
156
|
-
*/
|
|
157
|
-
function normalizeProjectPathForConfig(path) {
|
|
158
|
-
// Convert forward slashes to backslashes for Windows .claude.json format
|
|
159
|
-
let normalized = path.replace(/\//g, '\\');
|
|
160
|
-
|
|
161
|
-
// Handle /d/path format -> D:\path
|
|
162
|
-
if (normalized.match(/^\\[a-zA-Z]\\/)) {
|
|
163
|
-
normalized = normalized.charAt(1).toUpperCase() + ':' + normalized.slice(2);
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
return normalized;
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
/**
|
|
170
|
-
* Toggle MCP server enabled/disabled
|
|
171
|
-
* @param {string} projectPath
|
|
172
|
-
* @param {string} serverName
|
|
173
|
-
* @param {boolean} enable
|
|
174
|
-
* @returns {Object}
|
|
175
|
-
*/
|
|
176
|
-
function toggleMcpServerEnabled(projectPath, serverName, enable) {
|
|
177
|
-
try {
|
|
178
|
-
if (!existsSync(CLAUDE_CONFIG_PATH)) {
|
|
179
|
-
return { error: '.claude.json not found' };
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
const content = readFileSync(CLAUDE_CONFIG_PATH, 'utf8');
|
|
183
|
-
const config = JSON.parse(content);
|
|
184
|
-
|
|
185
|
-
const normalizedPath = normalizeProjectPathForConfig(projectPath);
|
|
186
|
-
|
|
187
|
-
if (!config.projects || !config.projects[normalizedPath]) {
|
|
188
|
-
return { error: `Project not found: ${normalizedPath}` };
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
const projectConfig = config.projects[normalizedPath];
|
|
192
|
-
|
|
193
|
-
// Ensure disabledMcpServers array exists
|
|
194
|
-
if (!projectConfig.disabledMcpServers) {
|
|
195
|
-
projectConfig.disabledMcpServers = [];
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
if (enable) {
|
|
199
|
-
// Remove from disabled list
|
|
200
|
-
projectConfig.disabledMcpServers = projectConfig.disabledMcpServers.filter(s => s !== serverName);
|
|
201
|
-
} else {
|
|
202
|
-
// Add to disabled list if not already there
|
|
203
|
-
if (!projectConfig.disabledMcpServers.includes(serverName)) {
|
|
204
|
-
projectConfig.disabledMcpServers.push(serverName);
|
|
205
|
-
}
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
// Write back to file
|
|
209
|
-
writeFileSync(CLAUDE_CONFIG_PATH, JSON.stringify(config, null, 2), 'utf8');
|
|
210
|
-
|
|
211
|
-
return {
|
|
212
|
-
success: true,
|
|
213
|
-
serverName,
|
|
214
|
-
enabled: enable,
|
|
215
|
-
disabledMcpServers: projectConfig.disabledMcpServers
|
|
216
|
-
};
|
|
217
|
-
} catch (error: unknown) {
|
|
218
|
-
console.error('Error toggling MCP server:', error);
|
|
219
|
-
return { error: (error as Error).message };
|
|
220
|
-
}
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
/**
|
|
224
|
-
* Add MCP server to project
|
|
225
|
-
* @param {string} projectPath
|
|
226
|
-
* @param {string} serverName
|
|
227
|
-
* @param {Object} serverConfig
|
|
228
|
-
* @returns {Object}
|
|
229
|
-
*/
|
|
230
|
-
function addMcpServerToProject(projectPath, serverName, serverConfig) {
|
|
231
|
-
try {
|
|
232
|
-
if (!existsSync(CLAUDE_CONFIG_PATH)) {
|
|
233
|
-
return { error: '.claude.json not found' };
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
const content = readFileSync(CLAUDE_CONFIG_PATH, 'utf8');
|
|
237
|
-
const config = JSON.parse(content);
|
|
238
|
-
|
|
239
|
-
const normalizedPath = normalizeProjectPathForConfig(projectPath);
|
|
240
|
-
|
|
241
|
-
// Create project entry if it doesn't exist
|
|
242
|
-
if (!config.projects) {
|
|
243
|
-
config.projects = {};
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
if (!config.projects[normalizedPath]) {
|
|
247
|
-
config.projects[normalizedPath] = {
|
|
248
|
-
allowedTools: [],
|
|
249
|
-
mcpContextUris: [],
|
|
250
|
-
mcpServers: {},
|
|
251
|
-
enabledMcpjsonServers: [],
|
|
252
|
-
disabledMcpjsonServers: [],
|
|
253
|
-
hasTrustDialogAccepted: false,
|
|
254
|
-
projectOnboardingSeenCount: 0,
|
|
255
|
-
hasClaudeMdExternalIncludesApproved: false,
|
|
256
|
-
hasClaudeMdExternalIncludesWarningShown: false
|
|
257
|
-
};
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
const projectConfig = config.projects[normalizedPath];
|
|
261
|
-
|
|
262
|
-
// Ensure mcpServers exists
|
|
263
|
-
if (!projectConfig.mcpServers) {
|
|
264
|
-
projectConfig.mcpServers = {};
|
|
265
|
-
}
|
|
266
|
-
|
|
267
|
-
// Add the server
|
|
268
|
-
projectConfig.mcpServers[serverName] = serverConfig;
|
|
269
|
-
|
|
270
|
-
// Write back to file
|
|
271
|
-
writeFileSync(CLAUDE_CONFIG_PATH, JSON.stringify(config, null, 2), 'utf8');
|
|
272
|
-
|
|
273
|
-
return {
|
|
274
|
-
success: true,
|
|
275
|
-
serverName,
|
|
276
|
-
serverConfig
|
|
277
|
-
};
|
|
278
|
-
} catch (error: unknown) {
|
|
279
|
-
console.error('Error adding MCP server:', error);
|
|
280
|
-
return { error: (error as Error).message };
|
|
281
|
-
}
|
|
282
|
-
}
|
|
283
|
-
|
|
284
|
-
/**
|
|
285
|
-
* Remove MCP server from project
|
|
286
|
-
* @param {string} projectPath
|
|
287
|
-
* @param {string} serverName
|
|
288
|
-
* @returns {Object}
|
|
289
|
-
*/
|
|
290
|
-
function removeMcpServerFromProject(projectPath, serverName) {
|
|
291
|
-
try {
|
|
292
|
-
if (!existsSync(CLAUDE_CONFIG_PATH)) {
|
|
293
|
-
return { error: '.claude.json not found' };
|
|
294
|
-
}
|
|
295
|
-
|
|
296
|
-
const content = readFileSync(CLAUDE_CONFIG_PATH, 'utf8');
|
|
297
|
-
const config = JSON.parse(content);
|
|
298
|
-
|
|
299
|
-
const normalizedPath = normalizeProjectPathForConfig(projectPath);
|
|
300
|
-
|
|
301
|
-
if (!config.projects || !config.projects[normalizedPath]) {
|
|
302
|
-
return { error: `Project not found: ${normalizedPath}` };
|
|
303
|
-
}
|
|
304
|
-
|
|
305
|
-
const projectConfig = config.projects[normalizedPath];
|
|
306
|
-
|
|
307
|
-
if (!projectConfig.mcpServers || !projectConfig.mcpServers[serverName]) {
|
|
308
|
-
return { error: `Server not found: ${serverName}` };
|
|
309
|
-
}
|
|
310
|
-
|
|
311
|
-
// Remove the server
|
|
312
|
-
delete projectConfig.mcpServers[serverName];
|
|
313
|
-
|
|
314
|
-
// Also remove from disabled list if present
|
|
315
|
-
if (projectConfig.disabledMcpServers) {
|
|
316
|
-
projectConfig.disabledMcpServers = projectConfig.disabledMcpServers.filter(s => s !== serverName);
|
|
317
|
-
}
|
|
318
|
-
|
|
319
|
-
// Write back to file
|
|
320
|
-
writeFileSync(CLAUDE_CONFIG_PATH, JSON.stringify(config, null, 2), 'utf8');
|
|
321
|
-
|
|
322
|
-
return {
|
|
323
|
-
success: true,
|
|
324
|
-
serverName,
|
|
325
|
-
removed: true
|
|
326
|
-
};
|
|
327
|
-
} catch (error: unknown) {
|
|
328
|
-
console.error('Error removing MCP server:', error);
|
|
329
|
-
return { error: (error as Error).message };
|
|
330
|
-
}
|
|
331
|
-
}
|
|
332
|
-
|
|
333
|
-
/**
|
|
334
|
-
* Add MCP server to global/user scope (top-level mcpServers in ~/.claude.json)
|
|
335
|
-
* @param {string} serverName
|
|
336
|
-
* @param {Object} serverConfig
|
|
337
|
-
* @returns {Object}
|
|
338
|
-
*/
|
|
339
|
-
function addGlobalMcpServer(serverName, serverConfig) {
|
|
340
|
-
try {
|
|
341
|
-
if (!existsSync(CLAUDE_CONFIG_PATH)) {
|
|
342
|
-
return { error: '.claude.json not found' };
|
|
343
|
-
}
|
|
344
|
-
|
|
345
|
-
const content = readFileSync(CLAUDE_CONFIG_PATH, 'utf8');
|
|
346
|
-
const config = JSON.parse(content);
|
|
347
|
-
|
|
348
|
-
// Ensure top-level mcpServers exists
|
|
349
|
-
if (!config.mcpServers) {
|
|
350
|
-
config.mcpServers = {};
|
|
351
|
-
}
|
|
352
|
-
|
|
353
|
-
// Add the server to top-level mcpServers
|
|
354
|
-
config.mcpServers[serverName] = serverConfig;
|
|
355
|
-
|
|
356
|
-
// Write back to file
|
|
357
|
-
writeFileSync(CLAUDE_CONFIG_PATH, JSON.stringify(config, null, 2), 'utf8');
|
|
358
|
-
|
|
359
|
-
return {
|
|
360
|
-
success: true,
|
|
361
|
-
serverName,
|
|
362
|
-
serverConfig,
|
|
363
|
-
scope: 'global'
|
|
364
|
-
};
|
|
365
|
-
} catch (error: unknown) {
|
|
366
|
-
console.error('Error adding global MCP server:', error);
|
|
367
|
-
return { error: (error as Error).message };
|
|
368
|
-
}
|
|
369
|
-
}
|
|
370
|
-
|
|
371
|
-
/**
|
|
372
|
-
* Remove MCP server from global/user scope (top-level mcpServers)
|
|
373
|
-
* @param {string} serverName
|
|
374
|
-
* @returns {Object}
|
|
375
|
-
*/
|
|
376
|
-
function removeGlobalMcpServer(serverName) {
|
|
377
|
-
try {
|
|
378
|
-
if (!existsSync(CLAUDE_CONFIG_PATH)) {
|
|
379
|
-
return { error: '.claude.json not found' };
|
|
380
|
-
}
|
|
381
|
-
|
|
382
|
-
const content = readFileSync(CLAUDE_CONFIG_PATH, 'utf8');
|
|
383
|
-
const config = JSON.parse(content);
|
|
384
|
-
|
|
385
|
-
if (!config.mcpServers || !config.mcpServers[serverName]) {
|
|
386
|
-
return { error: `Global server not found: ${serverName}` };
|
|
387
|
-
}
|
|
388
|
-
|
|
389
|
-
// Remove the server from top-level mcpServers
|
|
390
|
-
delete config.mcpServers[serverName];
|
|
391
|
-
|
|
392
|
-
// Write back to file
|
|
393
|
-
writeFileSync(CLAUDE_CONFIG_PATH, JSON.stringify(config, null, 2), 'utf8');
|
|
394
|
-
|
|
395
|
-
return {
|
|
396
|
-
success: true,
|
|
397
|
-
serverName,
|
|
398
|
-
removed: true,
|
|
399
|
-
scope: 'global'
|
|
400
|
-
};
|
|
401
|
-
} catch (error: unknown) {
|
|
402
|
-
console.error('Error removing global MCP server:', error);
|
|
403
|
-
return { error: (error as Error).message };
|
|
404
|
-
}
|
|
405
|
-
}
|
|
406
|
-
|
|
407
|
-
/**
|
|
408
|
-
* Read settings file safely
|
|
409
|
-
* @param {string} filePath
|
|
410
|
-
* @returns {Object}
|
|
411
|
-
*/
|
|
412
|
-
function readSettingsFile(filePath) {
|
|
413
|
-
try {
|
|
414
|
-
if (!existsSync(filePath)) {
|
|
415
|
-
return {};
|
|
416
|
-
}
|
|
417
|
-
const content = readFileSync(filePath, 'utf8');
|
|
418
|
-
return JSON.parse(content);
|
|
419
|
-
} catch (error: unknown) {
|
|
420
|
-
console.error(`Error reading settings file ${filePath}:`, error);
|
|
421
|
-
return {};
|
|
422
|
-
}
|
|
423
|
-
}
|
|
424
|
-
|
|
425
|
-
/**
|
|
426
|
-
* Write settings file safely
|
|
427
|
-
* @param {string} filePath
|
|
428
|
-
* @param {Object} settings
|
|
429
|
-
*/
|
|
430
|
-
function writeSettingsFile(filePath, settings) {
|
|
431
|
-
const dirPath = dirname(filePath);
|
|
432
|
-
// Ensure directory exists
|
|
433
|
-
if (!existsSync(dirPath)) {
|
|
434
|
-
mkdirSync(dirPath, { recursive: true });
|
|
435
|
-
}
|
|
436
|
-
writeFileSync(filePath, JSON.stringify(settings, null, 2), 'utf8');
|
|
437
|
-
}
|
|
438
|
-
|
|
439
|
-
/**
|
|
440
|
-
* Get project settings path
|
|
441
|
-
* @param {string} projectPath
|
|
442
|
-
* @returns {string}
|
|
443
|
-
*/
|
|
444
|
-
function getProjectSettingsPath(projectPath) {
|
|
445
|
-
const normalizedPath = projectPath.replace(/\//g, '\\').replace(/^\\([a-zA-Z])\\/, '$1:\\');
|
|
446
|
-
return join(normalizedPath, '.claude', 'settings.json');
|
|
447
|
-
}
|
|
448
|
-
|
|
449
|
-
// ========================================
|
|
450
|
-
// Route Handlers
|
|
451
|
-
// ========================================
|
|
452
|
-
|
|
453
|
-
/**
|
|
454
|
-
* Handle MCP routes
|
|
455
|
-
* @returns true if route was handled, false otherwise
|
|
456
|
-
*/
|
|
457
|
-
export async function handleMcpRoutes(ctx: RouteContext): Promise<boolean> {
|
|
458
|
-
const { pathname, url, req, res, initialPath, handlePostRequest, broadcastToClients } = ctx;
|
|
459
|
-
|
|
460
|
-
// API: Get MCP configuration
|
|
461
|
-
if (pathname === '/api/mcp-config') {
|
|
462
|
-
const mcpData = getMcpConfig();
|
|
463
|
-
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
464
|
-
res.end(JSON.stringify(mcpData));
|
|
465
|
-
return true;
|
|
466
|
-
}
|
|
467
|
-
|
|
468
|
-
// API: Toggle MCP server enabled/disabled
|
|
469
|
-
if (pathname === '/api/mcp-toggle' && req.method === 'POST') {
|
|
470
|
-
handlePostRequest(req, res, async (body) => {
|
|
471
|
-
const { projectPath, serverName, enable } = body;
|
|
472
|
-
if (!projectPath || !serverName) {
|
|
473
|
-
return { error: 'projectPath and serverName are required', status: 400 };
|
|
474
|
-
}
|
|
475
|
-
return toggleMcpServerEnabled(projectPath, serverName, enable);
|
|
476
|
-
});
|
|
477
|
-
return true;
|
|
478
|
-
}
|
|
479
|
-
|
|
480
|
-
// API: Copy MCP server to project
|
|
481
|
-
if (pathname === '/api/mcp-copy-server' && req.method === 'POST') {
|
|
482
|
-
handlePostRequest(req, res, async (body) => {
|
|
483
|
-
const { projectPath, serverName, serverConfig } = body;
|
|
484
|
-
if (!projectPath || !serverName || !serverConfig) {
|
|
485
|
-
return { error: 'projectPath, serverName, and serverConfig are required', status: 400 };
|
|
486
|
-
}
|
|
487
|
-
return addMcpServerToProject(projectPath, serverName, serverConfig);
|
|
488
|
-
});
|
|
489
|
-
return true;
|
|
490
|
-
}
|
|
491
|
-
|
|
492
|
-
// API: Install CCW MCP server to project
|
|
493
|
-
if (pathname === '/api/mcp-install-ccw' && req.method === 'POST') {
|
|
494
|
-
handlePostRequest(req, res, async (body) => {
|
|
495
|
-
const { projectPath } = body;
|
|
496
|
-
if (!projectPath) {
|
|
497
|
-
return { error: 'projectPath is required', status: 400 };
|
|
498
|
-
}
|
|
499
|
-
|
|
500
|
-
// Generate CCW MCP server config
|
|
501
|
-
const ccwMcpConfig = {
|
|
502
|
-
command: "ccw-mcp",
|
|
503
|
-
args: []
|
|
504
|
-
};
|
|
505
|
-
|
|
506
|
-
// Use existing addMcpServerToProject to install CCW MCP
|
|
507
|
-
return addMcpServerToProject(projectPath, 'ccw-mcp', ccwMcpConfig);
|
|
508
|
-
});
|
|
509
|
-
return true;
|
|
510
|
-
}
|
|
511
|
-
|
|
512
|
-
// API: Remove MCP server from project
|
|
513
|
-
if (pathname === '/api/mcp-remove-server' && req.method === 'POST') {
|
|
514
|
-
handlePostRequest(req, res, async (body) => {
|
|
515
|
-
const { projectPath, serverName } = body;
|
|
516
|
-
if (!projectPath || !serverName) {
|
|
517
|
-
return { error: 'projectPath and serverName are required', status: 400 };
|
|
518
|
-
}
|
|
519
|
-
return removeMcpServerFromProject(projectPath, serverName);
|
|
520
|
-
});
|
|
521
|
-
return true;
|
|
522
|
-
}
|
|
523
|
-
|
|
524
|
-
// API: Add MCP server to global scope (top-level mcpServers in ~/.claude.json)
|
|
525
|
-
if (pathname === '/api/mcp-add-global-server' && req.method === 'POST') {
|
|
526
|
-
handlePostRequest(req, res, async (body) => {
|
|
527
|
-
const { serverName, serverConfig } = body;
|
|
528
|
-
if (!serverName || !serverConfig) {
|
|
529
|
-
return { error: 'serverName and serverConfig are required', status: 400 };
|
|
530
|
-
}
|
|
531
|
-
return addGlobalMcpServer(serverName, serverConfig);
|
|
532
|
-
});
|
|
533
|
-
return true;
|
|
534
|
-
}
|
|
535
|
-
|
|
536
|
-
// API: Remove MCP server from global scope
|
|
537
|
-
if (pathname === '/api/mcp-remove-global-server' && req.method === 'POST') {
|
|
538
|
-
handlePostRequest(req, res, async (body) => {
|
|
539
|
-
const { serverName } = body;
|
|
540
|
-
if (!serverName) {
|
|
541
|
-
return { error: 'serverName is required', status: 400 };
|
|
542
|
-
}
|
|
543
|
-
return removeGlobalMcpServer(serverName);
|
|
544
|
-
});
|
|
545
|
-
return true;
|
|
546
|
-
}
|
|
547
|
-
|
|
548
|
-
return false;
|
|
549
|
-
}
|