vaspera-pm 2.10.0 → 2.10.2
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/dist/cli.js +231 -57
- package/dist/cli.js.map +1 -1
- package/dist/server.js +4 -2
- package/dist/server.js.map +1 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -292,11 +292,13 @@ async function validateApiKey(apiKey) {
|
|
|
292
292
|
}
|
|
293
293
|
};
|
|
294
294
|
}
|
|
295
|
+
const errorMessage = error2 instanceof Error ? error2.message : "Unknown error";
|
|
296
|
+
const isNetworkError = errorMessage.includes("ECONNREFUSED") || errorMessage.includes("ENOTFOUND") || errorMessage.includes("fetch failed") || errorMessage.includes("network");
|
|
295
297
|
return {
|
|
296
298
|
valid: false,
|
|
297
299
|
error: {
|
|
298
|
-
code: "VPM-INTERNAL-001",
|
|
299
|
-
message: "
|
|
300
|
+
code: isNetworkError ? "VPM-NETWORK-001" : "VPM-INTERNAL-001",
|
|
301
|
+
message: isNetworkError ? "Unable to reach VasperaPM servers. Check your internet connection or try again later." : `API key validation failed: ${errorMessage}`
|
|
300
302
|
}
|
|
301
303
|
};
|
|
302
304
|
}
|
|
@@ -31713,7 +31715,7 @@ var BANNER = `
|
|
|
31713
31715
|
\u2551 \u2551
|
|
31714
31716
|
\u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255D\x1B[0m
|
|
31715
31717
|
`;
|
|
31716
|
-
var VERSION7 = true ? "2.10.
|
|
31718
|
+
var VERSION7 = true ? "2.10.1" : "2.3.1";
|
|
31717
31719
|
var HELP = `
|
|
31718
31720
|
\x1B[1mUsage:\x1B[0m vaspera-pm <command> [path] [options]
|
|
31719
31721
|
|
|
@@ -31771,9 +31773,128 @@ var HELP = `
|
|
|
31771
31773
|
function getClaudeConfigPath() {
|
|
31772
31774
|
return join23(homedir2(), ".claude", "claude_desktop_config.json");
|
|
31773
31775
|
}
|
|
31776
|
+
function getCursorConfigPath() {
|
|
31777
|
+
return join23(homedir2(), ".cursor", "mcp.json");
|
|
31778
|
+
}
|
|
31779
|
+
function getProjectMcpConfigPath() {
|
|
31780
|
+
return join23(process.cwd(), ".mcp.json");
|
|
31781
|
+
}
|
|
31774
31782
|
function getVasperaConfigPath() {
|
|
31775
31783
|
return join23(homedir2(), ".vasperapm", "config.json");
|
|
31776
31784
|
}
|
|
31785
|
+
var VASPERA_PM_INSTRUCTIONS = `
|
|
31786
|
+
# VasperaPM Integration
|
|
31787
|
+
|
|
31788
|
+
This project uses VasperaPM for AI-powered product management.
|
|
31789
|
+
|
|
31790
|
+
## Available MCP Tools
|
|
31791
|
+
When VasperaPM MCP server is connected, you have access to these tools:
|
|
31792
|
+
- \`synthesize_requirements\` - Extract requirements from documents
|
|
31793
|
+
- \`infer_prd_from_code\` - Reverse-engineer PRD from code
|
|
31794
|
+
- \`verify_docs_code\` - Detect documentation drift
|
|
31795
|
+
- \`generate_api_docs\` - Create OpenAPI specifications
|
|
31796
|
+
- \`generate_test_specs\` - Generate test plans
|
|
31797
|
+
- \`sync_to_tracker\` - Export to Jira/Linear/GitHub/ADO
|
|
31798
|
+
- \`explode_backlog\` - Break features into user stories
|
|
31799
|
+
- \`review_prd\` - Quality review PRDs
|
|
31800
|
+
|
|
31801
|
+
## Usage Tips
|
|
31802
|
+
- Use \`verify_docs_code\` to check if documentation is in sync with code
|
|
31803
|
+
- Use \`generate_api_docs\` to auto-generate API documentation
|
|
31804
|
+
- Use \`sync_to_tracker\` to export requirements to your project tracker
|
|
31805
|
+
`;
|
|
31806
|
+
function updateProjectInstructions(projectId) {
|
|
31807
|
+
const cwd = process.cwd();
|
|
31808
|
+
const claudeMdPath = join23(cwd, "CLAUDE.md");
|
|
31809
|
+
const cursorRulesPath = join23(cwd, ".cursorrules");
|
|
31810
|
+
let targetFile;
|
|
31811
|
+
let existingContent = null;
|
|
31812
|
+
if (existsSync19(claudeMdPath)) {
|
|
31813
|
+
targetFile = claudeMdPath;
|
|
31814
|
+
existingContent = readFileSync15(claudeMdPath, "utf-8");
|
|
31815
|
+
} else if (existsSync19(cursorRulesPath)) {
|
|
31816
|
+
targetFile = cursorRulesPath;
|
|
31817
|
+
existingContent = readFileSync15(cursorRulesPath, "utf-8");
|
|
31818
|
+
} else {
|
|
31819
|
+
targetFile = claudeMdPath;
|
|
31820
|
+
}
|
|
31821
|
+
if (existingContent?.includes("# VasperaPM Integration")) {
|
|
31822
|
+
return { updated: false, file: targetFile, action: "Skipped" };
|
|
31823
|
+
}
|
|
31824
|
+
const projectSection = `
|
|
31825
|
+
## Project ID
|
|
31826
|
+
\`${projectId}\`
|
|
31827
|
+
`;
|
|
31828
|
+
const newContent = existingContent ? existingContent.trimEnd() + "\n\n---\n" + VASPERA_PM_INSTRUCTIONS + projectSection : VASPERA_PM_INSTRUCTIONS.trim() + projectSection;
|
|
31829
|
+
writeFileSync6(targetFile, newContent);
|
|
31830
|
+
return {
|
|
31831
|
+
updated: true,
|
|
31832
|
+
file: targetFile.split("/").pop() || targetFile,
|
|
31833
|
+
action: existingContent ? "Updated" : "Created"
|
|
31834
|
+
};
|
|
31835
|
+
}
|
|
31836
|
+
function detectMcpConfigLocations() {
|
|
31837
|
+
const locations = [
|
|
31838
|
+
{ path: getCursorConfigPath(), name: "Cursor (global)" },
|
|
31839
|
+
{ path: getClaudeConfigPath(), name: "Claude Desktop (global)" },
|
|
31840
|
+
{ path: getProjectMcpConfigPath(), name: "Project (.mcp.json)" }
|
|
31841
|
+
];
|
|
31842
|
+
return locations.map((loc) => {
|
|
31843
|
+
const config = readJsonFile(loc.path);
|
|
31844
|
+
return {
|
|
31845
|
+
...loc,
|
|
31846
|
+
exists: config !== null,
|
|
31847
|
+
hasVasperaPm: config?.mcpServers?.["vaspera-pm"] !== void 0
|
|
31848
|
+
};
|
|
31849
|
+
});
|
|
31850
|
+
}
|
|
31851
|
+
function mergeMcpConfig(configPath, vasperaApiKey, anthropicApiKey) {
|
|
31852
|
+
try {
|
|
31853
|
+
let config = readJsonFile(configPath);
|
|
31854
|
+
const existed = config !== null;
|
|
31855
|
+
if (!config) {
|
|
31856
|
+
config = { mcpServers: {} };
|
|
31857
|
+
}
|
|
31858
|
+
if (!config.mcpServers) {
|
|
31859
|
+
config.mcpServers = {};
|
|
31860
|
+
}
|
|
31861
|
+
const existingVpm = config.mcpServers["vaspera-pm"];
|
|
31862
|
+
if (existingVpm?.env?.VASPERA_API_KEY === vasperaApiKey) {
|
|
31863
|
+
return {
|
|
31864
|
+
success: true,
|
|
31865
|
+
path: configPath,
|
|
31866
|
+
action: "unchanged",
|
|
31867
|
+
message: "vaspera-pm already configured with same API key"
|
|
31868
|
+
};
|
|
31869
|
+
}
|
|
31870
|
+
const mcpEnv = {};
|
|
31871
|
+
if (vasperaApiKey && vasperaApiKey.startsWith("vpm_")) {
|
|
31872
|
+
mcpEnv.VASPERA_API_KEY = vasperaApiKey;
|
|
31873
|
+
}
|
|
31874
|
+
if (anthropicApiKey) {
|
|
31875
|
+
mcpEnv.ANTHROPIC_API_KEY = anthropicApiKey;
|
|
31876
|
+
}
|
|
31877
|
+
config.mcpServers["vaspera-pm"] = {
|
|
31878
|
+
command: "npx",
|
|
31879
|
+
args: ["-y", "vaspera-pm@latest", "serve"],
|
|
31880
|
+
env: mcpEnv
|
|
31881
|
+
};
|
|
31882
|
+
writeJsonFile(configPath, config);
|
|
31883
|
+
return {
|
|
31884
|
+
success: true,
|
|
31885
|
+
path: configPath,
|
|
31886
|
+
action: existed ? "updated" : "created",
|
|
31887
|
+
message: existed ? `Added vaspera-pm to existing config (${Object.keys(config.mcpServers).length} servers total)` : "Created new config with vaspera-pm"
|
|
31888
|
+
};
|
|
31889
|
+
} catch (err) {
|
|
31890
|
+
return {
|
|
31891
|
+
success: false,
|
|
31892
|
+
path: configPath,
|
|
31893
|
+
action: "error",
|
|
31894
|
+
message: err instanceof Error ? err.message : "Unknown error"
|
|
31895
|
+
};
|
|
31896
|
+
}
|
|
31897
|
+
}
|
|
31777
31898
|
function readJsonFile(path7) {
|
|
31778
31899
|
try {
|
|
31779
31900
|
if (!existsSync19(path7)) return null;
|
|
@@ -31816,23 +31937,20 @@ function warn(message) {
|
|
|
31816
31937
|
async function install() {
|
|
31817
31938
|
console.log(BANNER);
|
|
31818
31939
|
console.log("\x1B[1mInstalling VasperaPM for Claude Code...\x1B[0m\n");
|
|
31819
|
-
|
|
31820
|
-
|
|
31821
|
-
|
|
31822
|
-
|
|
31823
|
-
|
|
31824
|
-
|
|
31825
|
-
|
|
31826
|
-
|
|
31827
|
-
|
|
31828
|
-
|
|
31829
|
-
|
|
31830
|
-
const answer = await prompt("\nDo you want to reinstall? (y/N): ");
|
|
31831
|
-
if (answer.toLowerCase() !== "y") {
|
|
31832
|
-
info("Installation cancelled.");
|
|
31833
|
-
return;
|
|
31940
|
+
console.log("\x1B[1m1. Detecting MCP configurations...\x1B[0m\n");
|
|
31941
|
+
const configLocations = detectMcpConfigLocations();
|
|
31942
|
+
for (const loc of configLocations) {
|
|
31943
|
+
if (loc.exists) {
|
|
31944
|
+
if (loc.hasVasperaPm) {
|
|
31945
|
+
info(`${loc.name}: Found (vaspera-pm already configured)`);
|
|
31946
|
+
} else {
|
|
31947
|
+
success(`${loc.name}: Found (will add vaspera-pm)`);
|
|
31948
|
+
}
|
|
31949
|
+
} else {
|
|
31950
|
+
console.log(` \x1B[90m${loc.name}: Not found\x1B[0m`);
|
|
31834
31951
|
}
|
|
31835
31952
|
}
|
|
31953
|
+
console.log("\n\x1B[1m2. Checking API keys...\x1B[0m\n");
|
|
31836
31954
|
const vasperaConfig = readJsonFile(getVasperaConfigPath());
|
|
31837
31955
|
let vasperaApiKey = vasperaConfig?.apiKey || process.env.VASPERA_API_KEY || "";
|
|
31838
31956
|
let anthropicApiKey = process.env.ANTHROPIC_API_KEY || "";
|
|
@@ -31844,7 +31962,7 @@ async function install() {
|
|
|
31844
31962
|
info("Using local mode with your Anthropic API key");
|
|
31845
31963
|
vasperaApiKey = "";
|
|
31846
31964
|
} else {
|
|
31847
|
-
console.log("\
|
|
31965
|
+
console.log("\x1B[1mAPI Key Setup\x1B[0m");
|
|
31848
31966
|
console.log("\nVasperaPM needs an API key to work. Choose one:\n");
|
|
31849
31967
|
console.log(" \x1B[32mOption 1:\x1B[0m Connect to VasperaPM (recommended)");
|
|
31850
31968
|
console.log(" Run: \x1B[36mvasperapm connect\x1B[0m");
|
|
@@ -31866,19 +31984,43 @@ async function install() {
|
|
|
31866
31984
|
return;
|
|
31867
31985
|
}
|
|
31868
31986
|
}
|
|
31869
|
-
|
|
31870
|
-
|
|
31871
|
-
|
|
31987
|
+
console.log("\n\x1B[1m3. Select configurations to update\x1B[0m\n");
|
|
31988
|
+
const existingConfigs = configLocations.filter((c) => c.exists || c.name.includes("Project"));
|
|
31989
|
+
const configurableConfigs = existingConfigs.length > 0 ? existingConfigs : configLocations.slice(0, 2);
|
|
31990
|
+
console.log("Which MCP configurations should be updated?\n");
|
|
31991
|
+
for (let i = 0; i < configurableConfigs.length; i++) {
|
|
31992
|
+
const loc = configurableConfigs[i];
|
|
31993
|
+
const status2 = loc.hasVasperaPm ? " (already has vaspera-pm)" : "";
|
|
31994
|
+
console.log(` [${i + 1}] ${loc.name}${status2}`);
|
|
31872
31995
|
}
|
|
31873
|
-
|
|
31874
|
-
|
|
31996
|
+
console.log(` [a] All of the above`);
|
|
31997
|
+
console.log(` [n] None (just show instructions)
|
|
31998
|
+
`);
|
|
31999
|
+
const configChoice = await prompt("Select option(s) [1,2,a,n]: ");
|
|
32000
|
+
let selectedConfigs = [];
|
|
32001
|
+
if (configChoice.toLowerCase() === "a") {
|
|
32002
|
+
selectedConfigs = configurableConfigs;
|
|
32003
|
+
} else if (configChoice.toLowerCase() === "n") {
|
|
32004
|
+
selectedConfigs = [];
|
|
32005
|
+
} else {
|
|
32006
|
+
const indices = configChoice.split(",").map((s) => parseInt(s.trim(), 10) - 1);
|
|
32007
|
+
selectedConfigs = indices.filter((i) => i >= 0 && i < configurableConfigs.length).map((i) => configurableConfigs[i]);
|
|
32008
|
+
}
|
|
32009
|
+
if (selectedConfigs.length > 0) {
|
|
32010
|
+
console.log("\n\x1B[1m4. Applying configurations...\x1B[0m\n");
|
|
32011
|
+
for (const loc of selectedConfigs) {
|
|
32012
|
+
const result = mergeMcpConfig(loc.path, vasperaApiKey, anthropicApiKey);
|
|
32013
|
+
if (result.success) {
|
|
32014
|
+
if (result.action === "unchanged") {
|
|
32015
|
+
info(`${loc.name}: ${result.message}`);
|
|
32016
|
+
} else {
|
|
32017
|
+
success(`${loc.name}: ${result.message}`);
|
|
32018
|
+
}
|
|
32019
|
+
} else {
|
|
32020
|
+
error(`${loc.name}: ${result.message}`);
|
|
32021
|
+
}
|
|
32022
|
+
}
|
|
31875
32023
|
}
|
|
31876
|
-
config.mcpServers["vaspera-pm"] = {
|
|
31877
|
-
command: "vasperapm",
|
|
31878
|
-
args: ["serve"],
|
|
31879
|
-
env: mcpEnv
|
|
31880
|
-
};
|
|
31881
|
-
writeJsonFile(configPath, config);
|
|
31882
32024
|
if (vasperaApiKey && vasperaApiKey.startsWith("vpm_live_")) {
|
|
31883
32025
|
const vasperaDir = join23(homedir2(), ".vasperapm");
|
|
31884
32026
|
if (!existsSync19(vasperaDir)) {
|
|
@@ -31887,11 +32029,27 @@ async function install() {
|
|
|
31887
32029
|
writeJsonFile(getVasperaConfigPath(), { apiKey: vasperaApiKey });
|
|
31888
32030
|
}
|
|
31889
32031
|
console.log("\n");
|
|
31890
|
-
success("VasperaPM
|
|
32032
|
+
success("VasperaPM installation complete!");
|
|
31891
32033
|
console.log("\n\x1B[1mNext steps:\x1B[0m");
|
|
31892
|
-
|
|
31893
|
-
|
|
31894
|
-
|
|
32034
|
+
if (selectedConfigs.length > 0) {
|
|
32035
|
+
console.log(" 1. Restart your IDE (Cursor/VSCode/Claude Desktop)");
|
|
32036
|
+
console.log(" 2. Look for VasperaPM tools in the MCP panel");
|
|
32037
|
+
console.log(' 3. Try: "Generate a PRD for a todo app"\n');
|
|
32038
|
+
} else {
|
|
32039
|
+
console.log(" To manually configure MCP, add this to your mcp.json:\n");
|
|
32040
|
+
console.log(' \x1B[36m"vaspera-pm": {\x1B[0m');
|
|
32041
|
+
console.log(' \x1B[36m "command": "npx",\x1B[0m');
|
|
32042
|
+
console.log(' \x1B[36m "args": ["-y", "vaspera-pm@latest", "serve"],\x1B[0m');
|
|
32043
|
+
console.log(' \x1B[36m "env": {\x1B[0m');
|
|
32044
|
+
if (vasperaApiKey) {
|
|
32045
|
+
console.log(` \x1B[36m "VASPERA_API_KEY": "${vasperaApiKey}"\x1B[0m`);
|
|
32046
|
+
}
|
|
32047
|
+
if (anthropicApiKey) {
|
|
32048
|
+
console.log(` \x1B[36m "ANTHROPIC_API_KEY": "${anthropicApiKey.substring(0, 10)}..."\x1B[0m`);
|
|
32049
|
+
}
|
|
32050
|
+
console.log(" \x1B[36m }\x1B[0m");
|
|
32051
|
+
console.log(" \x1B[36m}\x1B[0m\n");
|
|
32052
|
+
}
|
|
31895
32053
|
console.log("\x1B[1mAvailable Tools (30 total):\x1B[0m");
|
|
31896
32054
|
console.log(" \x1B[33m\u2022\x1B[0m synthesize_requirements - Extract requirements from docs");
|
|
31897
32055
|
console.log(" \x1B[33m\u2022\x1B[0m infer_prd_from_code - Reverse-engineer PRD from code");
|
|
@@ -32100,6 +32258,10 @@ async function connect() {
|
|
|
32100
32258
|
success("Added .vaspera/ to .gitignore");
|
|
32101
32259
|
}
|
|
32102
32260
|
}
|
|
32261
|
+
const claudeMdResult = updateProjectInstructions(projectId);
|
|
32262
|
+
if (claudeMdResult.updated) {
|
|
32263
|
+
success(`${claudeMdResult.action} ${claudeMdResult.file} with VasperaPM context`);
|
|
32264
|
+
}
|
|
32103
32265
|
console.log("\n");
|
|
32104
32266
|
success("Project connected successfully!");
|
|
32105
32267
|
console.log("\n\x1B[1mConfiguration saved to:\x1B[0m .vaspera/config.json");
|
|
@@ -32207,13 +32369,25 @@ function parseOptions(args) {
|
|
|
32207
32369
|
}
|
|
32208
32370
|
return { path: path7, output, ci, verbose, agents, debate, format, files, noCache };
|
|
32209
32371
|
}
|
|
32372
|
+
function hasAIKey() {
|
|
32373
|
+
const vasperaKey = process.env.VASPERA_API_KEY;
|
|
32374
|
+
const anthropicKey = process.env.ANTHROPIC_API_KEY;
|
|
32375
|
+
return !!(vasperaKey && vasperaKey.startsWith("vpm_")) || !!anthropicKey;
|
|
32376
|
+
}
|
|
32377
|
+
function showAIKeyError() {
|
|
32378
|
+
error("API key required for AI-powered analysis");
|
|
32379
|
+
console.log("\nChoose one of these options:\n");
|
|
32380
|
+
console.log(" \x1B[32mOption 1:\x1B[0m Use your VasperaPM account (recommended)");
|
|
32381
|
+
console.log(" Run: \x1B[36mvasperapm connect\x1B[0m");
|
|
32382
|
+
console.log(" Then retry your command.\n");
|
|
32383
|
+
console.log(" \x1B[32mOption 2:\x1B[0m Use your own Anthropic API key");
|
|
32384
|
+
console.log(" \x1B[36mexport ANTHROPIC_API_KEY=sk-ant-xxx\x1B[0m");
|
|
32385
|
+
console.log(" Get one at: https://console.anthropic.com\n");
|
|
32386
|
+
}
|
|
32210
32387
|
async function runAnalyze(args) {
|
|
32211
32388
|
const options = parseOptions(args);
|
|
32212
|
-
if (!
|
|
32213
|
-
|
|
32214
|
-
console.log("\nSet your API key:");
|
|
32215
|
-
console.log(" export ANTHROPIC_API_KEY=sk-ant-xxx");
|
|
32216
|
-
console.log("\nOr get one at: https://console.anthropic.com\n");
|
|
32389
|
+
if (!hasAIKey()) {
|
|
32390
|
+
showAIKeyError();
|
|
32217
32391
|
process.exit(1);
|
|
32218
32392
|
}
|
|
32219
32393
|
if (options.agents) {
|
|
@@ -32497,8 +32671,8 @@ async function runVerify(args) {
|
|
|
32497
32671
|
fixPreference = args[++i];
|
|
32498
32672
|
}
|
|
32499
32673
|
}
|
|
32500
|
-
if (!
|
|
32501
|
-
|
|
32674
|
+
if (!hasAIKey()) {
|
|
32675
|
+
showAIKeyError();
|
|
32502
32676
|
process.exit(1);
|
|
32503
32677
|
}
|
|
32504
32678
|
if (options.format === "json" && suggestFixes) {
|
|
@@ -32610,8 +32784,8 @@ function formatFixSuggestionsForJSON(suggestions) {
|
|
|
32610
32784
|
}
|
|
32611
32785
|
async function runFix(args) {
|
|
32612
32786
|
const options = parseOptions(args);
|
|
32613
|
-
if (!
|
|
32614
|
-
|
|
32787
|
+
if (!hasAIKey()) {
|
|
32788
|
+
showAIKeyError();
|
|
32615
32789
|
process.exit(1);
|
|
32616
32790
|
}
|
|
32617
32791
|
let interactive = false;
|
|
@@ -32926,20 +33100,20 @@ async function runInit() {
|
|
|
32926
33100
|
};
|
|
32927
33101
|
writeJsonFile(configPath, config);
|
|
32928
33102
|
const mcpConfigPath = join23(process.cwd(), ".mcp.json");
|
|
32929
|
-
|
|
32930
|
-
|
|
32931
|
-
|
|
32932
|
-
|
|
32933
|
-
|
|
32934
|
-
|
|
32935
|
-
|
|
32936
|
-
|
|
32937
|
-
|
|
32938
|
-
|
|
32939
|
-
|
|
32940
|
-
}
|
|
32941
|
-
|
|
32942
|
-
|
|
33103
|
+
const mcpResult = mergeMcpConfig(
|
|
33104
|
+
mcpConfigPath,
|
|
33105
|
+
"",
|
|
33106
|
+
// No VasperaPM API key in init (uses ANTHROPIC_API_KEY)
|
|
33107
|
+
anthropicKey || "${ANTHROPIC_API_KEY}"
|
|
33108
|
+
);
|
|
33109
|
+
if (mcpResult.success) {
|
|
33110
|
+
if (mcpResult.action === "created") {
|
|
33111
|
+
success("Created .mcp.json for Claude Code integration");
|
|
33112
|
+
} else if (mcpResult.action === "updated") {
|
|
33113
|
+
success("Added vaspera-pm to existing .mcp.json (preserved other servers)");
|
|
33114
|
+
} else {
|
|
33115
|
+
info(".mcp.json already has vaspera-pm configured");
|
|
33116
|
+
}
|
|
32943
33117
|
}
|
|
32944
33118
|
console.log("\n");
|
|
32945
33119
|
success("VasperaPM initialized successfully!");
|