@smithery/cli 0.0.9 ā 0.0.10
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/README.md +0 -7
- package/dist/index.js +96 -45
- package/package.json +11 -11
- package/LICENSE +0 -21
- package/dist/auto-update.js +0 -33
- package/dist/commands/get.js +0 -25
- package/dist/commands/install.js +0 -76
- package/dist/commands/installed.js +0 -31
- package/dist/commands/list.js +0 -45
- package/dist/commands/uninstall.js +0 -47
- package/dist/install.js +0 -79
- package/dist/types/analytics.js +0 -1
- package/dist/types/index.js +0 -1
- package/dist/types/package.js +0 -1
- package/dist/types.js +0 -1
- package/dist/utils/analytics.js +0 -44
- package/dist/utils/config-manager.js +0 -122
- package/dist/utils/config.js +0 -74
- package/dist/utils/display.js +0 -39
- package/dist/utils/package-actions.js +0 -52
- package/dist/utils/package-management.js +0 -217
- package/dist/utils/package-resolver.js +0 -133
- package/dist/utils/runtime-utils.js +0 -37
- package/dist/utils/ui.js +0 -65
package/dist/utils/config.js
DELETED
|
@@ -1,74 +0,0 @@
|
|
|
1
|
-
import * as fs from "node:fs";
|
|
2
|
-
import * as path from "node:path";
|
|
3
|
-
import * as os from "node:os";
|
|
4
|
-
import { fileURLToPath } from "node:url";
|
|
5
|
-
import { dirname } from "node:path";
|
|
6
|
-
import { exec } from "node:child_process";
|
|
7
|
-
import { promisify } from "node:util";
|
|
8
|
-
const __filename = fileURLToPath(import.meta.url);
|
|
9
|
-
const __dirname = dirname(__filename);
|
|
10
|
-
const execAsync = promisify(exec);
|
|
11
|
-
export const VALID_CLIENTS = ["claude"];
|
|
12
|
-
function getPackageRuntime(packageName) {
|
|
13
|
-
const packageListPath = path.join(dirname(__dirname), "../packages/package-list.json");
|
|
14
|
-
if (!fs.existsSync(packageListPath)) {
|
|
15
|
-
return "node"; // Default to node if package list doesn't exist
|
|
16
|
-
}
|
|
17
|
-
const packageList = JSON.parse(fs.readFileSync(packageListPath, "utf8"));
|
|
18
|
-
const pkg = packageList.find((p) => p.name === packageName);
|
|
19
|
-
return pkg?.runtime || "node";
|
|
20
|
-
}
|
|
21
|
-
export function getConfigPath() {
|
|
22
|
-
if (process.platform === "win32") {
|
|
23
|
-
return path.join(process.env.APPDATA || "", "Claude", "claude_desktop_config.json");
|
|
24
|
-
}
|
|
25
|
-
const configDir = path.join(os.homedir(), "Library", "Application Support", "Claude");
|
|
26
|
-
return path.join(configDir, "claude_desktop_config.json");
|
|
27
|
-
}
|
|
28
|
-
export function readConfig() {
|
|
29
|
-
const configPath = getConfigPath();
|
|
30
|
-
if (!fs.existsSync(configPath)) {
|
|
31
|
-
return {};
|
|
32
|
-
}
|
|
33
|
-
return JSON.parse(fs.readFileSync(configPath, "utf8"));
|
|
34
|
-
}
|
|
35
|
-
export function writeConfig(config) {
|
|
36
|
-
const configPath = getConfigPath();
|
|
37
|
-
const configDir = path.dirname(configPath);
|
|
38
|
-
if (!fs.existsSync(configDir)) {
|
|
39
|
-
fs.mkdirSync(configDir, { recursive: true });
|
|
40
|
-
}
|
|
41
|
-
fs.writeFileSync(configPath, JSON.stringify(config, null, 2));
|
|
42
|
-
}
|
|
43
|
-
export async function installMCPServer(packageName, envVars, runtime) {
|
|
44
|
-
const config = readConfig();
|
|
45
|
-
const serverName = packageName.replace(/\//g, "-");
|
|
46
|
-
const effectiveRuntime = runtime || getPackageRuntime(packageName);
|
|
47
|
-
if (!config.mcpServers) {
|
|
48
|
-
config.mcpServers = {};
|
|
49
|
-
}
|
|
50
|
-
let command = "npx";
|
|
51
|
-
if (effectiveRuntime === "python") {
|
|
52
|
-
try {
|
|
53
|
-
const { stdout } = await execAsync("which uvx");
|
|
54
|
-
command = stdout.trim();
|
|
55
|
-
}
|
|
56
|
-
catch (error) {
|
|
57
|
-
command = "uvx"; // Fallback to just 'uvx' if which fails
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
const serverConfig = {
|
|
61
|
-
runtime: effectiveRuntime,
|
|
62
|
-
env: envVars,
|
|
63
|
-
command,
|
|
64
|
-
args: effectiveRuntime === "python" ? [packageName] : ["-y", packageName],
|
|
65
|
-
};
|
|
66
|
-
config.mcpServers[serverName] = serverConfig;
|
|
67
|
-
writeConfig(config);
|
|
68
|
-
}
|
|
69
|
-
export function envVarsToArgs(envVars) {
|
|
70
|
-
return Object.entries(envVars).flatMap(([key, value]) => {
|
|
71
|
-
const argName = key.toLowerCase().replace(/_/g, "-");
|
|
72
|
-
return [`--${argName}`, value];
|
|
73
|
-
});
|
|
74
|
-
}
|
package/dist/utils/display.js
DELETED
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
import chalk from "chalk";
|
|
2
|
-
import inquirer from "inquirer";
|
|
3
|
-
export async function displayPackageDetailsWithActions(pkg) {
|
|
4
|
-
console.log(`\n${chalk.bold.cyan("Package Details:")}`);
|
|
5
|
-
console.log(chalk.bold("ID: ") + pkg.id);
|
|
6
|
-
console.log(chalk.bold("Name: ") + pkg.name);
|
|
7
|
-
console.log(chalk.bold("Description: ") + pkg.description);
|
|
8
|
-
console.log(chalk.bold("Vendor: ") + pkg.vendor);
|
|
9
|
-
console.log(chalk.bold("License: ") + pkg.license);
|
|
10
|
-
// console.log(chalk.bold('Runtime: ') + (pkg.runtime || 'node'));
|
|
11
|
-
console.log(chalk.bold("Source: ") + (pkg.sourceUrl || "Not available"));
|
|
12
|
-
console.log(chalk.bold("Homepage: ") + (pkg.homepage || "Not available"));
|
|
13
|
-
console.log(chalk.bold("Status: ") +
|
|
14
|
-
(pkg.isInstalled ? chalk.green("Installed") : "Not installed") +
|
|
15
|
-
(pkg.isVerified ? "" : chalk.yellow(" (Unverified package)")));
|
|
16
|
-
const choices = [
|
|
17
|
-
{
|
|
18
|
-
name: pkg.isInstalled
|
|
19
|
-
? "š Reinstall this package"
|
|
20
|
-
: "š¦ Install this package",
|
|
21
|
-
value: "install",
|
|
22
|
-
},
|
|
23
|
-
...(pkg.isInstalled
|
|
24
|
-
? [{ name: "šļø Uninstall this package", value: "uninstall" }]
|
|
25
|
-
: []),
|
|
26
|
-
...(pkg.sourceUrl ? [{ name: "š Open source URL", value: "open" }] : []),
|
|
27
|
-
{ name: "ā¬
ļø Back to list", value: "back" },
|
|
28
|
-
{ name: "ā Exit", value: "exit" },
|
|
29
|
-
];
|
|
30
|
-
const { action } = await inquirer.prompt([
|
|
31
|
-
{
|
|
32
|
-
type: "list",
|
|
33
|
-
name: "action",
|
|
34
|
-
message: "What would you like to do?",
|
|
35
|
-
choices,
|
|
36
|
-
},
|
|
37
|
-
]);
|
|
38
|
-
return action;
|
|
39
|
-
}
|
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
import chalk from "chalk";
|
|
2
|
-
import { displayPackageDetailsWithActions } from "./display.js";
|
|
3
|
-
import { installPackage, uninstallPackage } from "./package-management.js";
|
|
4
|
-
import { confirmUninstall } from "./ui.js";
|
|
5
|
-
export async function handlePackageAction(pkg, action, handlers, showActionsAfter = true) {
|
|
6
|
-
switch (action) {
|
|
7
|
-
case "install":
|
|
8
|
-
console.log(chalk.cyan(`\nPreparing to install ${pkg.name}...`));
|
|
9
|
-
await installPackage(pkg);
|
|
10
|
-
pkg.isInstalled = true;
|
|
11
|
-
if (handlers.onInstall) {
|
|
12
|
-
await handlers.onInstall(pkg);
|
|
13
|
-
}
|
|
14
|
-
break;
|
|
15
|
-
case "uninstall":
|
|
16
|
-
if (await confirmUninstall(pkg.name)) {
|
|
17
|
-
await uninstallPackage(pkg.name);
|
|
18
|
-
console.log(chalk.green(`Successfully uninstalled ${pkg.name}`));
|
|
19
|
-
pkg.isInstalled = false;
|
|
20
|
-
if (handlers.onUninstall) {
|
|
21
|
-
await handlers.onUninstall(pkg);
|
|
22
|
-
return; // Don't show actions after uninstall if handler provided
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
else {
|
|
26
|
-
console.log("Uninstallation cancelled.");
|
|
27
|
-
}
|
|
28
|
-
break;
|
|
29
|
-
case "open":
|
|
30
|
-
if (pkg.sourceUrl) {
|
|
31
|
-
const open = (await import("open")).default;
|
|
32
|
-
await open(pkg.sourceUrl);
|
|
33
|
-
console.log(chalk.green(`\nOpened ${pkg.sourceUrl} in your browser`));
|
|
34
|
-
}
|
|
35
|
-
else {
|
|
36
|
-
console.log(chalk.yellow("\nNo source URL available for this package"));
|
|
37
|
-
}
|
|
38
|
-
break;
|
|
39
|
-
case "back":
|
|
40
|
-
if (handlers.onBack) {
|
|
41
|
-
await handlers.onBack();
|
|
42
|
-
}
|
|
43
|
-
return;
|
|
44
|
-
case "exit":
|
|
45
|
-
process.exit(0);
|
|
46
|
-
}
|
|
47
|
-
// Show actions again after completing an action (except for exit/back)
|
|
48
|
-
if (showActionsAfter) {
|
|
49
|
-
const nextAction = await displayPackageDetailsWithActions(pkg);
|
|
50
|
-
await handlePackageAction(pkg, nextAction, handlers);
|
|
51
|
-
}
|
|
52
|
-
}
|
|
@@ -1,217 +0,0 @@
|
|
|
1
|
-
import { exec } from "node:child_process";
|
|
2
|
-
import inquirer from "inquirer";
|
|
3
|
-
import { promisify } from "node:util";
|
|
4
|
-
import { ConfigManager } from "./config-manager.js";
|
|
5
|
-
import { analytics } from "./analytics.js";
|
|
6
|
-
const execAsync = promisify(exec);
|
|
7
|
-
async function checkAnalyticsConsent() {
|
|
8
|
-
const prefs = ConfigManager.readPreferences();
|
|
9
|
-
if (typeof prefs.allowAnalytics === "boolean") {
|
|
10
|
-
return prefs.allowAnalytics;
|
|
11
|
-
}
|
|
12
|
-
const { allowAnalytics } = await inquirer.prompt([
|
|
13
|
-
{
|
|
14
|
-
type: "confirm",
|
|
15
|
-
name: "allowAnalytics",
|
|
16
|
-
message: "Would you like to help improve @smithery/cli by sharing anonymous installation analytics?",
|
|
17
|
-
default: true,
|
|
18
|
-
},
|
|
19
|
-
]);
|
|
20
|
-
ConfigManager.writePreferences({ ...prefs, allowAnalytics });
|
|
21
|
-
return allowAnalytics;
|
|
22
|
-
}
|
|
23
|
-
async function trackInstallation(packageName, client) {
|
|
24
|
-
return analytics.trackInstallation(packageName, client);
|
|
25
|
-
}
|
|
26
|
-
async function promptForPlaceholder(key, message) {
|
|
27
|
-
const { value } = await inquirer.prompt([
|
|
28
|
-
{
|
|
29
|
-
type: "input",
|
|
30
|
-
name: "value",
|
|
31
|
-
message: message || `Please enter value for ${key}:`,
|
|
32
|
-
validate: (input) => (input ? true : `${key} is required`),
|
|
33
|
-
},
|
|
34
|
-
]);
|
|
35
|
-
return value;
|
|
36
|
-
}
|
|
37
|
-
async function promptForEnvVars(pkg) {
|
|
38
|
-
const connection = pkg.connections?.[0];
|
|
39
|
-
if (!connection?.stdio) {
|
|
40
|
-
return undefined;
|
|
41
|
-
}
|
|
42
|
-
const envVars = {};
|
|
43
|
-
const placeholderPattern = /\${(\w+)}/;
|
|
44
|
-
// Handle env variables
|
|
45
|
-
if (connection.stdio.env) {
|
|
46
|
-
for (const [key, value] of Object.entries(connection.stdio.env)) {
|
|
47
|
-
const match = String(value).match(placeholderPattern);
|
|
48
|
-
if (!match)
|
|
49
|
-
continue;
|
|
50
|
-
const varName = match[1];
|
|
51
|
-
const existingEnvVar = process.env[key];
|
|
52
|
-
if (existingEnvVar) {
|
|
53
|
-
const { reuseExisting } = await inquirer.prompt([
|
|
54
|
-
{
|
|
55
|
-
type: "confirm",
|
|
56
|
-
name: "reuseExisting",
|
|
57
|
-
message: `Found ${key} in your environment variables. Would you like to use it?`,
|
|
58
|
-
default: true,
|
|
59
|
-
},
|
|
60
|
-
]);
|
|
61
|
-
if (reuseExisting) {
|
|
62
|
-
envVars[key] = existingEnvVar;
|
|
63
|
-
continue;
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
envVars[key] = await promptForPlaceholder(key);
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
// Handle args placeholders
|
|
70
|
-
if (connection.stdio.args) {
|
|
71
|
-
for (let i = 0; i < connection.stdio.args.length; i++) {
|
|
72
|
-
const arg = connection.stdio.args[i];
|
|
73
|
-
const match = String(arg).match(placeholderPattern);
|
|
74
|
-
if (!match)
|
|
75
|
-
continue;
|
|
76
|
-
const varName = match[1];
|
|
77
|
-
const value = await promptForPlaceholder(varName);
|
|
78
|
-
connection.stdio.args[i] = arg.replace(placeholderPattern, value);
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
return Object.keys(envVars).length > 0 ? envVars : undefined;
|
|
82
|
-
}
|
|
83
|
-
async function isClientRunning(client) {
|
|
84
|
-
if (!client)
|
|
85
|
-
return false;
|
|
86
|
-
try {
|
|
87
|
-
const platform = process.platform;
|
|
88
|
-
// Map of supported clients to their process names
|
|
89
|
-
// Currently only Claude is officially supported
|
|
90
|
-
// Other entries are placeholders for future integrations
|
|
91
|
-
const clientProcess = {
|
|
92
|
-
claude: "Claude",
|
|
93
|
-
// jan: "Jan", // Placeholder for future client integration
|
|
94
|
-
// Add more clients here as they become supported
|
|
95
|
-
}[client] || client;
|
|
96
|
-
if (platform === "win32") {
|
|
97
|
-
const { stdout } = await execAsync(`tasklist /FI "IMAGENAME eq ${clientProcess}.exe" /NH`);
|
|
98
|
-
return stdout.includes(`${clientProcess}.exe`);
|
|
99
|
-
}
|
|
100
|
-
else if (platform === "darwin") {
|
|
101
|
-
const { stdout } = await execAsync(`pgrep -x "${clientProcess}"`);
|
|
102
|
-
return !!stdout.trim();
|
|
103
|
-
}
|
|
104
|
-
else if (platform === "linux") {
|
|
105
|
-
const { stdout } = await execAsync(`pgrep -f "${clientProcess.toLowerCase()}"`);
|
|
106
|
-
return !!stdout.trim();
|
|
107
|
-
}
|
|
108
|
-
return false;
|
|
109
|
-
}
|
|
110
|
-
catch (error) {
|
|
111
|
-
// If the command fails, assume client is not running
|
|
112
|
-
return false;
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
async function restartClient(client) {
|
|
116
|
-
const clientProcess = {
|
|
117
|
-
claude: "Claude",
|
|
118
|
-
jan: "Jan",
|
|
119
|
-
// Add more clients here
|
|
120
|
-
}[client] || client;
|
|
121
|
-
try {
|
|
122
|
-
const platform = process.platform;
|
|
123
|
-
if (platform === "win32") {
|
|
124
|
-
await execAsync(`taskkill /F /IM "${clientProcess}.exe" && start "" "${clientProcess}.exe"`);
|
|
125
|
-
}
|
|
126
|
-
else if (platform === "darwin") {
|
|
127
|
-
await execAsync(`killall "${clientProcess}" && open -a "${clientProcess}"`);
|
|
128
|
-
}
|
|
129
|
-
else if (platform === "linux") {
|
|
130
|
-
await execAsync(`pkill -f "${clientProcess.toLowerCase()}" && ${clientProcess.toLowerCase()}`);
|
|
131
|
-
}
|
|
132
|
-
// Wait a moment for the app to close before reopening
|
|
133
|
-
await new Promise((resolve) => setTimeout(resolve, 2000));
|
|
134
|
-
// Reopen the app
|
|
135
|
-
if (platform === "win32") {
|
|
136
|
-
await execAsync(`start "" "${clientProcess}.exe"`);
|
|
137
|
-
}
|
|
138
|
-
else if (platform === "darwin") {
|
|
139
|
-
await execAsync(`open -a "${clientProcess}"`);
|
|
140
|
-
}
|
|
141
|
-
else if (platform === "linux") {
|
|
142
|
-
await execAsync(clientProcess.toLowerCase());
|
|
143
|
-
}
|
|
144
|
-
console.log(`${clientProcess} has been restarted.`);
|
|
145
|
-
}
|
|
146
|
-
catch (error) {
|
|
147
|
-
console.error(`Failed to restart ${clientProcess}:`, error);
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
async function promptForRestart(client) {
|
|
151
|
-
if (!client)
|
|
152
|
-
return false;
|
|
153
|
-
// Check if client is running first
|
|
154
|
-
const isRunning = await isClientRunning(client);
|
|
155
|
-
if (!isRunning) {
|
|
156
|
-
return false;
|
|
157
|
-
}
|
|
158
|
-
const { shouldRestart } = await inquirer.prompt([
|
|
159
|
-
{
|
|
160
|
-
type: "confirm",
|
|
161
|
-
name: "shouldRestart",
|
|
162
|
-
message: `Would you like to restart the ${client} app to apply changes?`,
|
|
163
|
-
default: true,
|
|
164
|
-
},
|
|
165
|
-
]);
|
|
166
|
-
if (shouldRestart) {
|
|
167
|
-
console.log(`Restarting ${client} app...`);
|
|
168
|
-
await restartClient(client);
|
|
169
|
-
}
|
|
170
|
-
return shouldRestart;
|
|
171
|
-
}
|
|
172
|
-
export async function installPackage(pkg) {
|
|
173
|
-
try {
|
|
174
|
-
// Temporarily bypass UV check for Python packages
|
|
175
|
-
/* if (pkg.runtime === 'python') {
|
|
176
|
-
const hasUV = await checkUVInstalled();
|
|
177
|
-
if (!hasUV) {
|
|
178
|
-
const installed = await promptForUVInstall(inquirer);
|
|
179
|
-
if (!installed) {
|
|
180
|
-
console.log('Proceeding with installation, but uvx commands may fail...');
|
|
181
|
-
}
|
|
182
|
-
}
|
|
183
|
-
} */
|
|
184
|
-
const envVars = await promptForEnvVars(pkg);
|
|
185
|
-
// Use the connection stdio config directly
|
|
186
|
-
const connection = pkg.connections?.[0];
|
|
187
|
-
const serverConfig = {
|
|
188
|
-
command: connection.stdio.command,
|
|
189
|
-
args: connection.stdio.args,
|
|
190
|
-
env: {
|
|
191
|
-
...(envVars || {}),
|
|
192
|
-
},
|
|
193
|
-
};
|
|
194
|
-
// Install package with client-specific configuration
|
|
195
|
-
await ConfigManager.installPackage(pkg.id, serverConfig, pkg.client);
|
|
196
|
-
console.log(`Updated ${pkg.client || "default"} configuration`);
|
|
197
|
-
if (await checkAnalyticsConsent()) {
|
|
198
|
-
await trackInstallation(pkg.id, pkg.client);
|
|
199
|
-
}
|
|
200
|
-
await promptForRestart(pkg.client);
|
|
201
|
-
}
|
|
202
|
-
catch (error) {
|
|
203
|
-
console.error("Failed to install package:", error);
|
|
204
|
-
throw error;
|
|
205
|
-
}
|
|
206
|
-
}
|
|
207
|
-
export async function uninstallPackage(packageName, client) {
|
|
208
|
-
try {
|
|
209
|
-
await ConfigManager.uninstallPackage(packageName);
|
|
210
|
-
console.log(`\nUninstalled ${packageName}`);
|
|
211
|
-
await promptForRestart(client);
|
|
212
|
-
}
|
|
213
|
-
catch (error) {
|
|
214
|
-
console.error("Failed to uninstall package:", error);
|
|
215
|
-
throw error;
|
|
216
|
-
}
|
|
217
|
-
}
|
|
@@ -1,133 +0,0 @@
|
|
|
1
|
-
import { ConfigManager } from "./config-manager.js";
|
|
2
|
-
// import path from 'path';
|
|
3
|
-
// import fs from 'fs';
|
|
4
|
-
// import { dirname } from 'path';
|
|
5
|
-
// import { fileURLToPath } from 'url';
|
|
6
|
-
import dotenv from "dotenv";
|
|
7
|
-
dotenv.config();
|
|
8
|
-
export const REGISTRY_ENDPOINT = process.env.REGISTRY_ENDPOINT || "https://registry.smithery.ai";
|
|
9
|
-
export function isPackageInstalled(packageName) {
|
|
10
|
-
return ConfigManager.isPackageInstalled(packageName);
|
|
11
|
-
}
|
|
12
|
-
export async function resolvePackages(client) {
|
|
13
|
-
try {
|
|
14
|
-
// Updated API endpoint
|
|
15
|
-
const response = await fetch(`${REGISTRY_ENDPOINT}/servers/`);
|
|
16
|
-
if (!response.ok) {
|
|
17
|
-
throw new Error(`Failed to fetch packages: ${response.statusText} (${response.status})`);
|
|
18
|
-
}
|
|
19
|
-
// Add text validation before JSON parsing
|
|
20
|
-
const text = await response.text();
|
|
21
|
-
if (!text) {
|
|
22
|
-
throw new Error("Empty response received from registry");
|
|
23
|
-
}
|
|
24
|
-
let packages;
|
|
25
|
-
try {
|
|
26
|
-
packages = JSON.parse(text);
|
|
27
|
-
}
|
|
28
|
-
catch (parseError) {
|
|
29
|
-
const errorMessage = parseError instanceof Error
|
|
30
|
-
? parseError.message
|
|
31
|
-
: "Unknown parsing error";
|
|
32
|
-
throw new Error(`Invalid JSON response from registry: ${errorMessage}`);
|
|
33
|
-
}
|
|
34
|
-
const resolvedPackages = new Map();
|
|
35
|
-
// Add packages from registry
|
|
36
|
-
for (const pkg of packages) {
|
|
37
|
-
resolvedPackages.set(pkg.id, {
|
|
38
|
-
id: pkg.id || "",
|
|
39
|
-
name: pkg.name || "",
|
|
40
|
-
description: pkg.description || "",
|
|
41
|
-
vendor: pkg.vendor || "",
|
|
42
|
-
sourceUrl: pkg.sourceUrl || "",
|
|
43
|
-
license: pkg.license || "",
|
|
44
|
-
connections: pkg.connections || [],
|
|
45
|
-
homepage: pkg.homepage || "",
|
|
46
|
-
isInstalled: false,
|
|
47
|
-
isVerified: true,
|
|
48
|
-
client: client,
|
|
49
|
-
});
|
|
50
|
-
}
|
|
51
|
-
// Process installed packages
|
|
52
|
-
const config = ConfigManager.readConfig();
|
|
53
|
-
const installedIds = Object.keys(config.mcpServers || {});
|
|
54
|
-
const installedServers = config.mcpServers || {};
|
|
55
|
-
for (const id of installedIds) {
|
|
56
|
-
const installedServer = installedServers[id];
|
|
57
|
-
const existingPkg = resolvedPackages.get(id);
|
|
58
|
-
if (existingPkg) {
|
|
59
|
-
resolvedPackages.set(id, {
|
|
60
|
-
...existingPkg,
|
|
61
|
-
isInstalled: true,
|
|
62
|
-
client: client || existingPkg.client,
|
|
63
|
-
});
|
|
64
|
-
}
|
|
65
|
-
else {
|
|
66
|
-
resolvedPackages.set(id, {
|
|
67
|
-
...installedServer,
|
|
68
|
-
id: id || "",
|
|
69
|
-
name: id || "",
|
|
70
|
-
description: "Local package",
|
|
71
|
-
vendor: "Local",
|
|
72
|
-
sourceUrl: "",
|
|
73
|
-
license: "",
|
|
74
|
-
connections: [],
|
|
75
|
-
homepage: "",
|
|
76
|
-
isInstalled: true,
|
|
77
|
-
isVerified: false,
|
|
78
|
-
client: client,
|
|
79
|
-
});
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
return Array.from(resolvedPackages.values());
|
|
83
|
-
}
|
|
84
|
-
catch (error) {
|
|
85
|
-
throw new Error(`Failed to resolve packages: ${error instanceof Error ? error.message : String(error)}`);
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
export async function resolvePackage(packageId, client) {
|
|
89
|
-
try {
|
|
90
|
-
// Updated API endpoint
|
|
91
|
-
const response = await fetch(`${REGISTRY_ENDPOINT}/servers/${packageId}`);
|
|
92
|
-
if (!response.ok) {
|
|
93
|
-
// Check if it's an installed package
|
|
94
|
-
const config = ConfigManager.readConfig();
|
|
95
|
-
const installedServer = config.mcpServers?.[packageId];
|
|
96
|
-
if (installedServer) {
|
|
97
|
-
return {
|
|
98
|
-
id: packageId,
|
|
99
|
-
name: packageId,
|
|
100
|
-
description: "Local package",
|
|
101
|
-
vendor: "Local",
|
|
102
|
-
sourceUrl: "",
|
|
103
|
-
license: "",
|
|
104
|
-
connections: [],
|
|
105
|
-
homepage: "",
|
|
106
|
-
isInstalled: true,
|
|
107
|
-
isVerified: false,
|
|
108
|
-
client: client,
|
|
109
|
-
};
|
|
110
|
-
}
|
|
111
|
-
return null;
|
|
112
|
-
}
|
|
113
|
-
const registryPackage = await response.json();
|
|
114
|
-
const resolvedPackage = {
|
|
115
|
-
id: registryPackage.id,
|
|
116
|
-
name: registryPackage.name,
|
|
117
|
-
description: registryPackage.description,
|
|
118
|
-
vendor: registryPackage.vendor,
|
|
119
|
-
sourceUrl: registryPackage.sourceUrl,
|
|
120
|
-
license: registryPackage.license,
|
|
121
|
-
connections: registryPackage.connections,
|
|
122
|
-
homepage: registryPackage.homepage,
|
|
123
|
-
isInstalled: isPackageInstalled(registryPackage.id),
|
|
124
|
-
isVerified: true,
|
|
125
|
-
client: client,
|
|
126
|
-
};
|
|
127
|
-
return resolvedPackage;
|
|
128
|
-
}
|
|
129
|
-
catch (error) {
|
|
130
|
-
console.error("Error resolving package:", error);
|
|
131
|
-
return null;
|
|
132
|
-
}
|
|
133
|
-
}
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
import { exec } from "node:child_process";
|
|
2
|
-
import { promisify } from "node:util";
|
|
3
|
-
import chalk from "chalk";
|
|
4
|
-
const execAsync = promisify(exec);
|
|
5
|
-
export async function checkUVInstalled() {
|
|
6
|
-
try {
|
|
7
|
-
await execAsync("uvx --version");
|
|
8
|
-
return true;
|
|
9
|
-
}
|
|
10
|
-
catch (error) {
|
|
11
|
-
return false;
|
|
12
|
-
}
|
|
13
|
-
}
|
|
14
|
-
export async function promptForUVInstall(inquirerInstance) {
|
|
15
|
-
const { shouldInstall } = await inquirerInstance.prompt([
|
|
16
|
-
{
|
|
17
|
-
type: "confirm",
|
|
18
|
-
name: "shouldInstall",
|
|
19
|
-
message: "UV package manager is required for Python MCP servers. Would you like to install it?",
|
|
20
|
-
default: true,
|
|
21
|
-
},
|
|
22
|
-
]);
|
|
23
|
-
if (!shouldInstall) {
|
|
24
|
-
console.warn(chalk.yellow("UV installation was declined. You can install it manually from https://astral.sh/uv"));
|
|
25
|
-
return false;
|
|
26
|
-
}
|
|
27
|
-
console.log("Installing uv package manager...");
|
|
28
|
-
try {
|
|
29
|
-
await execAsync("curl -LsSf https://astral.sh/uv/install.sh | sh");
|
|
30
|
-
console.log(chalk.green("ā UV installed successfully"));
|
|
31
|
-
return true;
|
|
32
|
-
}
|
|
33
|
-
catch (error) {
|
|
34
|
-
console.warn(chalk.yellow("Failed to install UV. You can install it manually from https://astral.sh/uv"));
|
|
35
|
-
return false;
|
|
36
|
-
}
|
|
37
|
-
}
|
package/dist/utils/ui.js
DELETED
|
@@ -1,65 +0,0 @@
|
|
|
1
|
-
import inquirer from "inquirer";
|
|
2
|
-
import fuzzy from "fuzzy";
|
|
3
|
-
import chalk from "chalk";
|
|
4
|
-
export function formatPackageChoice(pkg, showInstallStatus = false) {
|
|
5
|
-
const prefix = showInstallStatus ? (pkg.isInstalled ? "ā " : " ") : "";
|
|
6
|
-
const name = (pkg.name || "").toString();
|
|
7
|
-
const description = (pkg.description || "").toString();
|
|
8
|
-
const vendor = (pkg.vendor || "").toString();
|
|
9
|
-
const id = (pkg.id || "").toString();
|
|
10
|
-
// Adjust column widths (removed license column)
|
|
11
|
-
const nameWidth = 20;
|
|
12
|
-
const idWidth = 15;
|
|
13
|
-
const descWidth = 45; // Increased description width
|
|
14
|
-
const vendorWidth = 15;
|
|
15
|
-
// Truncation function remains the same
|
|
16
|
-
const truncateText = (text, width) => {
|
|
17
|
-
if (text.length <= width) {
|
|
18
|
-
return text.padEnd(width);
|
|
19
|
-
}
|
|
20
|
-
return `${text.slice(0, width - 3).padEnd(width - 3)}...`;
|
|
21
|
-
};
|
|
22
|
-
// Apply truncation (removed license)
|
|
23
|
-
const truncatedName = truncateText(name, nameWidth);
|
|
24
|
-
const truncatedId = truncateText(id, idWidth);
|
|
25
|
-
const truncatedDesc = truncateText(description, descWidth);
|
|
26
|
-
const truncatedVendor = truncateText(vendor, vendorWidth);
|
|
27
|
-
return {
|
|
28
|
-
name: `${prefix}${truncatedName} ā ${truncatedId} ā ${truncatedDesc} ā ${truncatedVendor}`,
|
|
29
|
-
value: pkg,
|
|
30
|
-
short: name,
|
|
31
|
-
};
|
|
32
|
-
}
|
|
33
|
-
export function createPackagePrompt(packages, options = {}) {
|
|
34
|
-
const choices = packages.map((pkg) => formatPackageChoice(pkg, options.showInstallStatus));
|
|
35
|
-
return {
|
|
36
|
-
type: "autocomplete",
|
|
37
|
-
name: "selectedPackage",
|
|
38
|
-
message: options.message || "Search and select a package:",
|
|
39
|
-
source: async (_answersSoFar, input) => {
|
|
40
|
-
if (!input)
|
|
41
|
-
return choices;
|
|
42
|
-
return fuzzy
|
|
43
|
-
.filter(input.toLowerCase(), choices, {
|
|
44
|
-
extract: (choice) => `${choice.value.name} ${choice.value.description} ${choice.value.vendor}`.toLowerCase(),
|
|
45
|
-
})
|
|
46
|
-
.map((result) => result.original);
|
|
47
|
-
},
|
|
48
|
-
pageSize: 10,
|
|
49
|
-
};
|
|
50
|
-
}
|
|
51
|
-
export async function confirmUninstall(packageName) {
|
|
52
|
-
const { confirmUninstall } = await inquirer.prompt([
|
|
53
|
-
{
|
|
54
|
-
type: "confirm",
|
|
55
|
-
name: "confirmUninstall",
|
|
56
|
-
message: `Are you sure you want to uninstall ${packageName}?`,
|
|
57
|
-
default: false,
|
|
58
|
-
},
|
|
59
|
-
]);
|
|
60
|
-
return confirmUninstall;
|
|
61
|
-
}
|
|
62
|
-
export function printPackageListHeader(count, type = "all") {
|
|
63
|
-
console.log(chalk.bold.cyan(`\nš¦ ${type === "installed" ? "Installed Packages" : "Available Packages"}`));
|
|
64
|
-
console.log(chalk.gray(`Found ${count} ${type === "installed" ? "installed " : ""}packages\n`));
|
|
65
|
-
}
|