Skip to content

Commit

Permalink
fix: resolve TypeScript errors and update client configuration
Browse files Browse the repository at this point in the history
Co-Authored-By: Michael Latman <[email protected]>
  • Loading branch information
devin-ai-integration[bot] and michaellatman committed Dec 11, 2024
1 parent 7413cba commit 0bc79c1
Show file tree
Hide file tree
Showing 4 changed files with 64 additions and 50 deletions.
6 changes: 3 additions & 3 deletions src/__tests__/clients/zed-adapter.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -116,8 +116,7 @@ describe('ZedAdapter', () => {
const mockToml = `[context-servers]
[context-servers.test-server]
command = "node"
args = ["server.js"]
transport = "stdio"`;
args = ["server.js"]`;

(fs.readFile as jest.MockedFunction<typeof fs.readFile>)
.mockResolvedValueOnce(mockToml);
Expand All @@ -129,7 +128,8 @@ transport = "stdio"`;
const writtenConfig = TOML.parse(writeCall[1] as string) as unknown as TOMLConfig;
expect(writtenConfig['context-servers']).toBeDefined();
expect(writtenConfig['context-servers'][config.name]).toBeDefined();
expect(writtenConfig['context-servers'][config.name].transport).toBe('stdio');
expect(writtenConfig['context-servers'][config.name].command).toBe('node');
expect(writtenConfig['context-servers'][config.name].args).toEqual(['server.js']);
});

it('should write JSON settings with comments', async () => {
Expand Down
9 changes: 5 additions & 4 deletions src/__tests__/commands/clients.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { jest, describe, it, expect, beforeEach } from '@jest/globals';
import { listClients } from '../../commands/clients.js';
import { Preferences } from '../../utils/preferences.js';
import { Preferences, ClientType } from '../../utils/preferences.js';

jest.mock('../../utils/preferences.js');

Expand All @@ -10,8 +10,8 @@ describe('listClients', () => {
});

it('should display installed clients and config paths', async () => {
const mockClients = ['claude', 'zed'];
(Preferences.prototype.detectInstalledClients as jest.Mock).mockResolvedValue(mockClients);
const mockClients: ClientType[] = ['claude', 'zed'];
(Preferences.prototype.detectInstalledClients as jest.Mock<() => Promise<ClientType[]>>).mockImplementation(() => Promise.resolve(mockClients));

const consoleSpy = jest.spyOn(console, 'log');
await listClients();
Expand All @@ -21,7 +21,8 @@ describe('listClients', () => {
});

it('should handle no installed clients', async () => {
(Preferences.prototype.detectInstalledClients as jest.Mock).mockResolvedValue([]);
const emptyClients: ClientType[] = [];
(Preferences.prototype.detectInstalledClients as jest.Mock<() => Promise<ClientType[]>>).mockImplementation(() => Promise.resolve(emptyClients));

const consoleSpy = jest.spyOn(console, 'log');
await listClients();
Expand Down
2 changes: 0 additions & 2 deletions src/types/package.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,6 @@ export interface Package {
sourceUrl: string;
homepage: string;
license: string;
supportedClients?: ('claude' | 'zed' | 'continue' | 'firebase')[];
supportedTransports?: ('stdio' | 'sse' | 'websocket')[];
}

export interface ResolvedPackage extends Package {
Expand Down
97 changes: 56 additions & 41 deletions src/utils/package-management.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { packageHelpers } from '../helpers/index.js';
import { checkUVInstalled, promptForUVInstall } from './runtime-utils.js';
import { ConfigManager } from './config-manager.js';
import { ClientType } from '../types/client-config.js';
import { Preferences } from './preferences.js';

declare function fetch(url: string, init?: any): Promise<{ ok: boolean; statusText: string }>;

Expand Down Expand Up @@ -143,65 +144,75 @@ async function promptForEnvVars(packageName: string): Promise<Record<string, str
return envVars;
}

async function isClaudeRunning(): Promise<boolean> {
async function isClientRunning(clientType: ClientType): Promise<boolean> {
try {
const platform = process.platform;
if (platform === 'win32') {
const { stdout } = await execAsync('tasklist /FI "IMAGENAME eq Claude.exe" /NH');
return stdout.includes('Claude.exe');
} else if (platform === 'darwin') {
const { stdout } = await execAsync('pgrep -x "Claude"');
return !!stdout.trim();
} else if (platform === 'linux') {
const { stdout } = await execAsync('pgrep -f "claude"');
return !!stdout.trim();
switch (clientType) {
case 'claude':
if (platform === 'win32') {
const { stdout } = await execAsync('tasklist /FI "IMAGENAME eq Claude.exe" /NH');
return stdout.includes('Claude.exe');
} else if (platform === 'darwin') {
const { stdout } = await execAsync('pgrep -x "Claude"');
return !!stdout.trim();
} else if (platform === 'linux') {
const { stdout } = await execAsync('pgrep -f "claude"');
return !!stdout.trim();
}
break;
// Other clients don't require process checking
default:
return false;
}
return false;
} catch (error) {
return false;
}
}

async function promptForRestart(): Promise<boolean> {
const claudeRunning = await isClaudeRunning();
if (!claudeRunning) {
async function promptForRestart(clientType: ClientType): Promise<boolean> {
const clientRunning = await isClientRunning(clientType);
if (!clientRunning) {
return false;
}

const { shouldRestart } = await inquirer.prompt<{ shouldRestart: boolean }>([
{
type: 'confirm',
name: 'shouldRestart',
message: 'Would you like to restart the Claude desktop app to apply changes?',
message: `Would you like to restart the ${clientType} app to apply changes?`,
default: true
}
]);

if (shouldRestart) {
console.log('Restarting Claude desktop app...');
console.log(`Restarting ${clientType} app...`);
try {
const platform = process.platform;
if (platform === 'win32') {
await execAsync('taskkill /F /IM "Claude.exe" && start "" "Claude.exe"');
} else if (platform === 'darwin') {
await execAsync('killall "Claude" && open -a "Claude"');
} else if (platform === 'linux') {
await execAsync('pkill -f "claude" && claude');
}
if (clientType === 'claude') {
if (platform === 'win32') {
await execAsync('taskkill /F /IM "Claude.exe" && start "" "Claude.exe"');
} else if (platform === 'darwin') {
await execAsync('killall "Claude" && open -a "Claude"');
} else if (platform === 'linux') {
await execAsync('pkill -f "claude" && claude');
}

await new Promise(resolve => setTimeout(resolve, 2000));
await new Promise(resolve => setTimeout(resolve, 2000));

if (platform === 'win32') {
await execAsync('start "" "Claude.exe"');
} else if (platform === 'darwin') {
await execAsync('open -a "Claude"');
} else if (platform === 'linux') {
await execAsync('claude');
if (platform === 'win32') {
await execAsync('start "" "Claude.exe"');
} else if (platform === 'darwin') {
await execAsync('open -a "Claude"');
} else if (platform === 'linux') {
await execAsync('claude');
}
}
// Other clients don't require restart

console.log('Claude desktop app has been restarted.');
console.log(`${clientType} app has been restarted.`);
} catch (error) {
console.error('Failed to restart Claude desktop app:', error);
console.error(`Failed to restart ${clientType} app:`, error);
}
}

Expand Down Expand Up @@ -231,13 +242,15 @@ export async function installPackage(pkg: Package): Promise<void> {
}

const envVars = await promptForEnvVars(pkg.name);
const configManager = new ConfigManager();
const clients = await configManager.getInstalledClients();
const preferences = new Preferences();
const clients = await preferences.getOrSelectDefaultClients();
let selectedClient: ClientType;

if (clients.length > 1) {
const selectedClient = await promptForClientSelection(clients as ClientType[]);
selectedClient = await promptForClientSelection(clients);
await ConfigManager.installPackage(pkg, [selectedClient]);
} else if (clients.length === 1) {
selectedClient = clients[0];
await ConfigManager.installPackage(pkg, clients);
} else {
throw new Error('No MCP clients installed');
Expand All @@ -249,7 +262,7 @@ export async function installPackage(pkg: Package): Promise<void> {
await trackInstallation(pkg.name);
}

await promptForRestart();
await promptForRestart(selectedClient);
} catch (error) {
console.error('Failed to install package:', error);
throw error;
Expand All @@ -268,22 +281,24 @@ export async function uninstallPackage(packageName: string): Promise<void> {
runtime: 'node'
};

const configManager = new ConfigManager();
const clients = await configManager.getInstalledClients();
const preferences = new Preferences();
const clients = await preferences.getOrSelectDefaultClients();
let selectedClient: ClientType;

if (clients.length > 1) {
const selectedClient = await promptForClientSelection(clients);
await ConfigManager.uninstallPackage(pkg, [selectedClient as ClientType]);
selectedClient = await promptForClientSelection(clients);
await ConfigManager.uninstallPackage(pkg, [selectedClient]);
} else if (clients.length === 1) {
selectedClient = clients[0];
await ConfigManager.uninstallPackage(pkg, clients);
} else {
throw new Error('No MCP clients installed');
}

console.log(`\nUninstalled ${packageName}`);
await promptForRestart();
await promptForRestart(selectedClient);
} catch (error) {
console.error('Failed to uninstall package:', error);
throw error;
}
}
}

0 comments on commit 0bc79c1

Please sign in to comment.