decocms
Version:
CLI for managing deco.chat apps & projects
158 lines • 5.96 kB
JavaScript
/**
* Prompts the user to make their IDE sentient about the project by installing MCP configurations.
*
* This function:
* 1. Asks the user if they want to make their IDE sentient
* 2. If yes, prompts them to select their IDE (Cursor, VSCode, or Windsurf)
* 3. Returns the appropriate MCP configuration and target path for the selected IDE
*
* @param mcpConfig - The MCP configuration object
* @param projectRoot - The root path of the project where the config should be written
* @returns Promise<{ config: any; targetPath: string } | null> - The MCP config and target path, or null if user declines
*/
import inquirer from "inquirer";
import { promises as fs } from "fs";
import { dirname, join } from "path";
import { ensureDir } from "./fs.js";
import { getAppUUID, getMCPConfig, getMCPConfigVersion, getRulesConfig, } from "./config.js";
import process from "node:process";
const IDE_SUPPORT = {
cursor: {
name: "Cursor",
createConfig: async (mcpConfig, projectRoot) => {
const outDir = join(projectRoot, ".cursor");
const configs = [];
const configPath = join(outDir, "mcp.json");
const existingConfig = await fs
.readFile(configPath, "utf-8")
.then(JSON.parse)
.catch(() => ({ mcpServers: {} }));
const config = {
mcpServers: {
...(existingConfig.mcpServers || {}),
...mcpConfig.mcpServers,
},
};
configs.push({
content: JSON.stringify(config, null, 2),
path: join(outDir, "mcp.json"),
});
const rules = Object.entries(await getRulesConfig());
for (const [path, content] of rules) {
configs.push({ content, path: join(outDir, "rules", path) });
}
return configs;
},
},
vscode: {
name: "VS Code",
createConfig: async (mcpConfig, projectRoot) => {
const outDir = join(projectRoot, ".vscode");
const configs = [];
const configPath = join(outDir, "mcp.json");
const existingConfig = await fs
.readFile(configPath, "utf-8")
.then(JSON.parse)
.catch(() => ({ mcpServers: {} }));
const config = {
mcpServers: {
...(existingConfig.mcpServers || {}),
...mcpConfig.mcpServers,
},
};
configs.push({
content: JSON.stringify(config, null, 2),
path: join(outDir, "mcp.json"),
});
const rules = Object.entries(await getRulesConfig());
for (const [path, content] of rules) {
configs.push({ content, path: join(outDir, "rules", path) });
}
return configs;
},
},
};
export async function writeIDEConfig(configs) {
const targetDir = dirname(configs[0]?.path ?? "");
// Write all configuration files in parallel
await Promise.all(configs.map(async ({ content, path }) => {
await ensureDir(dirname(path));
await fs.writeFile(path, content);
}));
console.log(`✅ IDE configuration written to: ${targetDir}`);
}
export const hasMCPPreferences = async (workspace, app) => {
const [appUUID, currentVersion] = await Promise.all([
getAppUUID(workspace, app),
getMCPConfigVersion(),
]);
// Use a simple file-based storage instead of localStorage for Node.js
const prefsPath = join(process.cwd(), ".deco", "preferences.json");
try {
const prefs = JSON.parse(await fs.readFile(prefsPath, "utf-8"));
const storedVersion = prefs[`mcp-install-version-${appUUID}`];
return storedVersion === currentVersion;
}
catch {
return false;
}
};
export const setMCPPreferences = async (workspace, app) => {
const [appUUID, currentVersion] = await Promise.all([
getAppUUID(workspace, app),
getMCPConfigVersion(),
]);
const prefsPath = join(process.cwd(), ".deco", "preferences.json");
try {
await ensureDir(dirname(prefsPath));
let prefs = {};
try {
prefs = JSON.parse(await fs.readFile(prefsPath, "utf-8"));
}
catch {
// File doesn't exist, start with empty prefs
}
prefs[`mcp-install-version-${appUUID}`] = currentVersion;
await fs.writeFile(prefsPath, JSON.stringify(prefs, null, 2));
}
catch (error) {
console.warn("Failed to save MCP preferences:", error);
}
};
export async function promptIDESetup(cfg, projectRoot = process.cwd()) {
await setMCPPreferences(cfg.workspace, cfg.app);
const mcpConfig = getMCPConfig(cfg.workspace, cfg.app);
// Ask if user wants to make IDE sentient
const { wantsSentientIDE } = await inquirer.prompt([
{
type: "confirm",
name: "wantsSentientIDE",
message: "Would you like to configure your IDE to use this project?",
default: true,
},
]);
if (!wantsSentientIDE) {
return null;
}
// Prompt user to select their IDE
const { selectedIDE } = await inquirer.prompt([
{
type: "list",
name: "selectedIDE",
message: "Select your preferred IDE:",
choices: [
{ name: "Cursor", value: "cursor" },
{ name: "VS Code", value: "vscode" },
{ name: "None", value: "none" },
],
},
]);
const ideSupport = IDE_SUPPORT[selectedIDE];
if (selectedIDE === "none") {
return null;
}
// Create the IDE-specific configuration
const configs = await ideSupport.createConfig(mcpConfig, projectRoot);
return configs;
}
//# sourceMappingURL=prompt-ide-setup.js.map