feat(mosaic): migrate install wizard from v0 to v1 (#103)
All checks were successful
ci/woodpecker/push/ci Pipeline was successful
All checks were successful
ci/woodpecker/push/ci Pipeline was successful
Co-authored-by: Jason Woltje <jason@diversecanvas.com> Co-committed-by: Jason Woltje <jason@diversecanvas.com>
This commit was merged in pull request #103.
This commit is contained in:
95
packages/mosaic/src/runtime/mcp-config.ts
Normal file
95
packages/mosaic/src/runtime/mcp-config.ts
Normal file
@@ -0,0 +1,95 @@
|
||||
import { readFileSync, writeFileSync, existsSync, mkdirSync } from 'node:fs';
|
||||
import { join, dirname } from 'node:path';
|
||||
import { homedir } from 'node:os';
|
||||
import type { RuntimeName } from '../types.js';
|
||||
|
||||
const MCP_ENTRY = {
|
||||
command: 'npx',
|
||||
args: ['-y', '@modelcontextprotocol/server-sequential-thinking'],
|
||||
};
|
||||
|
||||
export function configureMcpForRuntime(runtime: RuntimeName): void {
|
||||
switch (runtime) {
|
||||
case 'claude':
|
||||
return configureClaudeMcp();
|
||||
case 'codex':
|
||||
return configureCodexMcp();
|
||||
case 'opencode':
|
||||
return configureOpenCodeMcp();
|
||||
}
|
||||
}
|
||||
|
||||
function ensureDir(filePath: string): void {
|
||||
mkdirSync(dirname(filePath), { recursive: true });
|
||||
}
|
||||
|
||||
function configureClaudeMcp(): void {
|
||||
const settingsPath = join(homedir(), '.claude', 'settings.json');
|
||||
ensureDir(settingsPath);
|
||||
|
||||
let data: Record<string, unknown> = {};
|
||||
if (existsSync(settingsPath)) {
|
||||
try {
|
||||
data = JSON.parse(readFileSync(settingsPath, 'utf-8')) as Record<string, unknown>;
|
||||
} catch {
|
||||
// Start fresh if corrupt
|
||||
}
|
||||
}
|
||||
|
||||
if (
|
||||
!data['mcpServers'] ||
|
||||
typeof data['mcpServers'] !== 'object' ||
|
||||
Array.isArray(data['mcpServers'])
|
||||
) {
|
||||
data['mcpServers'] = {};
|
||||
}
|
||||
(data['mcpServers'] as Record<string, unknown>)['sequential-thinking'] = MCP_ENTRY;
|
||||
|
||||
writeFileSync(settingsPath, JSON.stringify(data, null, 2) + '\n', 'utf-8');
|
||||
}
|
||||
|
||||
function configureCodexMcp(): void {
|
||||
const configPath = join(homedir(), '.codex', 'config.toml');
|
||||
ensureDir(configPath);
|
||||
|
||||
let content = '';
|
||||
if (existsSync(configPath)) {
|
||||
content = readFileSync(configPath, 'utf-8');
|
||||
// Remove existing sequential-thinking section
|
||||
content = content
|
||||
.replace(/\[mcp_servers\.(sequential-thinking|sequential_thinking)\][\s\S]*?(?=\n\[|$)/g, '')
|
||||
.trim();
|
||||
}
|
||||
|
||||
content +=
|
||||
'\n\n[mcp_servers.sequential-thinking]\n' +
|
||||
'command = "npx"\n' +
|
||||
'args = ["-y", "@modelcontextprotocol/server-sequential-thinking"]\n';
|
||||
|
||||
writeFileSync(configPath, content, 'utf-8');
|
||||
}
|
||||
|
||||
function configureOpenCodeMcp(): void {
|
||||
const configPath = join(homedir(), '.config', 'opencode', 'config.json');
|
||||
ensureDir(configPath);
|
||||
|
||||
let data: Record<string, unknown> = {};
|
||||
if (existsSync(configPath)) {
|
||||
try {
|
||||
data = JSON.parse(readFileSync(configPath, 'utf-8')) as Record<string, unknown>;
|
||||
} catch {
|
||||
// Start fresh
|
||||
}
|
||||
}
|
||||
|
||||
if (!data['mcp'] || typeof data['mcp'] !== 'object' || Array.isArray(data['mcp'])) {
|
||||
data['mcp'] = {};
|
||||
}
|
||||
(data['mcp'] as Record<string, unknown>)['sequential-thinking'] = {
|
||||
type: 'local',
|
||||
command: ['npx', '-y', '@modelcontextprotocol/server-sequential-thinking'],
|
||||
enabled: true,
|
||||
};
|
||||
|
||||
writeFileSync(configPath, JSON.stringify(data, null, 2) + '\n', 'utf-8');
|
||||
}
|
||||
Reference in New Issue
Block a user