diff --git a/src/installer/targets/deepcode.ts b/src/installer/targets/deepcode.ts new file mode 100644 index 000000000..1be4f7c74 --- /dev/null +++ b/src/installer/targets/deepcode.ts @@ -0,0 +1,115 @@ +/** + * DeepCode target. Writes the MCP server entry into DeepCode's settings + * file (`~/.deepcode/settings.json`). DeepCode has a single user-level + * config — global and local both write here. + * + * See https://deepcode.vegamo.cn/docs/configuration/mcp + */ + +import * as fs from 'fs'; +import * as path from 'path'; +import * as os from 'os'; +import { + AgentTarget, + DetectionResult, + InstallOptions, + Location, + WriteResult, +} from './types'; +import { + getMcpServerConfig, + jsonDeepEqual, + readJsonFile, + writeJsonFile, +} from './shared'; + +function configDir(_loc: Location): string { + return path.join(os.homedir(), '.deepcode'); +} + +function settingsPath(loc: Location): string { + return path.join(configDir(loc), 'settings.json'); +} + +class DeepcodeTarget implements AgentTarget { + readonly id = 'deepcode' as const; + readonly displayName = 'DeepCode'; + + supportsLocation(_loc: Location): boolean { + return true; + } + + detect(loc: Location): DetectionResult { + const file = settingsPath(loc); + const config = readJsonFile(file); + const alreadyConfigured = !!config.mcpServers?.codegraph; + const installed = fs.existsSync(configDir(loc)) || fs.existsSync(file); + return { installed, alreadyConfigured, configPath: file }; + } + + install(loc: Location, _opts: InstallOptions): WriteResult { + const files: WriteResult['files'] = []; + + // 1. MCP server entry + files.push(writeMcpEntry(loc)); + + return { + files, + notes: [ + 'Restart DeepCode for MCP changes to take effect.', + ], + }; + } + + uninstall(loc: Location): WriteResult { + const files: WriteResult['files'] = []; + + // 1. MCP server entry + const file = settingsPath(loc); + const config = readJsonFile(file); + if (config.mcpServers?.codegraph) { + delete config.mcpServers.codegraph; + if (Object.keys(config.mcpServers).length === 0) { + delete config.mcpServers; + } + writeJsonFile(file, config); + files.push({ path: file, action: 'removed' }); + } else { + files.push({ path: file, action: 'not-found' }); + } + + return { files }; + } + + printConfig(loc: Location): string { + const target = settingsPath(loc); + const snippet = JSON.stringify({ mcpServers: { codegraph: getMcpServerConfig() } }, null, 2); + return `# Add to ${target}\n\n${snippet}\n`; + } + + describePaths(loc: Location): string[] { + return [settingsPath(loc)]; + } +} + +function writeMcpEntry(loc: Location): WriteResult['files'][number] { + const file = settingsPath(loc); + const dir = path.dirname(file); + if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true }); + + const existing = readJsonFile(file); + const before = existing.mcpServers?.codegraph; + const after = getMcpServerConfig(); + + if (jsonDeepEqual(before, after)) { + return { path: file, action: 'unchanged' }; + } + const action: 'created' | 'updated' = + before ? 'updated' : (fs.existsSync(file) ? 'updated' : 'created'); + if (!existing.mcpServers) existing.mcpServers = {}; + existing.mcpServers.codegraph = after; + writeJsonFile(file, existing); + return { path: file, action }; +} + +export const deepcodeTarget: AgentTarget = new DeepcodeTarget(); diff --git a/src/installer/targets/registry.ts b/src/installer/targets/registry.ts index 5e929d468..618ade9ce 100644 --- a/src/installer/targets/registry.ts +++ b/src/installer/targets/registry.ts @@ -16,6 +16,7 @@ import { hermesTarget } from './hermes'; import { geminiTarget } from './gemini'; import { antigravityTarget } from './antigravity'; import { kiroTarget } from './kiro'; +import { deepcodeTarget } from './deepcode'; export const ALL_TARGETS: readonly AgentTarget[] = Object.freeze([ claudeTarget, @@ -26,6 +27,7 @@ export const ALL_TARGETS: readonly AgentTarget[] = Object.freeze([ geminiTarget, antigravityTarget, kiroTarget, + deepcodeTarget, ]); export function getTarget(id: string): AgentTarget | undefined { diff --git a/src/installer/targets/types.ts b/src/installer/targets/types.ts index 833a801ae..823345483 100644 --- a/src/installer/targets/types.ts +++ b/src/installer/targets/types.ts @@ -19,7 +19,7 @@ export type Location = 'global' | 'local'; * lookup. New targets add a value here when they're added to the * registry. Keep these short and lowercase. */ -export type TargetId = 'claude' | 'cursor' | 'codex' | 'opencode' | 'hermes' | 'gemini' | 'antigravity' | 'kiro'; +export type TargetId = 'claude' | 'cursor' | 'codex' | 'opencode' | 'hermes' | 'gemini' | 'antigravity' | 'kiro' | 'deepcode'; /** * Result of `target.detect(location)`.