imcp 0.0.1

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.
Files changed (124) hide show
  1. package/.github/ISSUE_TEMPLATE/JitAccess.yml +28 -0
  2. package/.github/acl/access.yml +20 -0
  3. package/.github/compliance/inventory.yml +5 -0
  4. package/.github/policies/jit.yml +19 -0
  5. package/README.md +137 -0
  6. package/dist/cli/commands/install.d.ts +2 -0
  7. package/dist/cli/commands/install.js +105 -0
  8. package/dist/cli/commands/list.d.ts +2 -0
  9. package/dist/cli/commands/list.js +90 -0
  10. package/dist/cli/commands/pull.d.ts +2 -0
  11. package/dist/cli/commands/pull.js +17 -0
  12. package/dist/cli/commands/serve.d.ts +2 -0
  13. package/dist/cli/commands/serve.js +32 -0
  14. package/dist/cli/commands/start.d.ts +2 -0
  15. package/dist/cli/commands/start.js +32 -0
  16. package/dist/cli/commands/sync.d.ts +2 -0
  17. package/dist/cli/commands/sync.js +17 -0
  18. package/dist/cli/commands/uninstall.d.ts +2 -0
  19. package/dist/cli/commands/uninstall.js +39 -0
  20. package/dist/cli/index.d.ts +2 -0
  21. package/dist/cli/index.js +114 -0
  22. package/dist/core/ConfigurationProvider.d.ts +31 -0
  23. package/dist/core/ConfigurationProvider.js +416 -0
  24. package/dist/core/InstallationService.d.ts +17 -0
  25. package/dist/core/InstallationService.js +144 -0
  26. package/dist/core/MCPManager.d.ts +17 -0
  27. package/dist/core/MCPManager.js +98 -0
  28. package/dist/core/RequirementService.d.ts +45 -0
  29. package/dist/core/RequirementService.js +123 -0
  30. package/dist/core/constants.d.ts +29 -0
  31. package/dist/core/constants.js +55 -0
  32. package/dist/core/installers/BaseInstaller.d.ts +73 -0
  33. package/dist/core/installers/BaseInstaller.js +247 -0
  34. package/dist/core/installers/ClientInstaller.d.ts +17 -0
  35. package/dist/core/installers/ClientInstaller.js +307 -0
  36. package/dist/core/installers/CommandInstaller.d.ts +36 -0
  37. package/dist/core/installers/CommandInstaller.js +170 -0
  38. package/dist/core/installers/GeneralInstaller.d.ts +32 -0
  39. package/dist/core/installers/GeneralInstaller.js +87 -0
  40. package/dist/core/installers/InstallerFactory.d.ts +52 -0
  41. package/dist/core/installers/InstallerFactory.js +95 -0
  42. package/dist/core/installers/NpmInstaller.d.ts +25 -0
  43. package/dist/core/installers/NpmInstaller.js +123 -0
  44. package/dist/core/installers/PipInstaller.d.ts +25 -0
  45. package/dist/core/installers/PipInstaller.js +114 -0
  46. package/dist/core/installers/RequirementInstaller.d.ts +32 -0
  47. package/dist/core/installers/RequirementInstaller.js +3 -0
  48. package/dist/core/installers/index.d.ts +6 -0
  49. package/dist/core/installers/index.js +7 -0
  50. package/dist/core/types.d.ts +152 -0
  51. package/dist/core/types.js +16 -0
  52. package/dist/index.d.ts +11 -0
  53. package/dist/index.js +19 -0
  54. package/dist/services/InstallRequestValidator.d.ts +21 -0
  55. package/dist/services/InstallRequestValidator.js +99 -0
  56. package/dist/services/ServerService.d.ts +47 -0
  57. package/dist/services/ServerService.js +145 -0
  58. package/dist/utils/UpdateCheckTracker.d.ts +39 -0
  59. package/dist/utils/UpdateCheckTracker.js +80 -0
  60. package/dist/utils/clientUtils.d.ts +29 -0
  61. package/dist/utils/clientUtils.js +105 -0
  62. package/dist/utils/feedUtils.d.ts +5 -0
  63. package/dist/utils/feedUtils.js +29 -0
  64. package/dist/utils/githubAuth.d.ts +1 -0
  65. package/dist/utils/githubAuth.js +123 -0
  66. package/dist/utils/logger.d.ts +14 -0
  67. package/dist/utils/logger.js +90 -0
  68. package/dist/utils/osUtils.d.ts +16 -0
  69. package/dist/utils/osUtils.js +235 -0
  70. package/dist/web/public/css/modal.css +250 -0
  71. package/dist/web/public/css/notifications.css +70 -0
  72. package/dist/web/public/index.html +157 -0
  73. package/dist/web/public/js/api.js +213 -0
  74. package/dist/web/public/js/modal.js +572 -0
  75. package/dist/web/public/js/notifications.js +99 -0
  76. package/dist/web/public/js/serverCategoryDetails.js +210 -0
  77. package/dist/web/public/js/serverCategoryList.js +82 -0
  78. package/dist/web/public/modal.html +61 -0
  79. package/dist/web/public/styles.css +155 -0
  80. package/dist/web/server.d.ts +5 -0
  81. package/dist/web/server.js +150 -0
  82. package/package.json +53 -0
  83. package/src/cli/commands/install.ts +140 -0
  84. package/src/cli/commands/list.ts +112 -0
  85. package/src/cli/commands/pull.ts +16 -0
  86. package/src/cli/commands/serve.ts +37 -0
  87. package/src/cli/commands/uninstall.ts +54 -0
  88. package/src/cli/index.ts +127 -0
  89. package/src/core/ConfigurationProvider.ts +489 -0
  90. package/src/core/InstallationService.ts +173 -0
  91. package/src/core/MCPManager.ts +134 -0
  92. package/src/core/RequirementService.ts +147 -0
  93. package/src/core/constants.ts +61 -0
  94. package/src/core/installers/BaseInstaller.ts +292 -0
  95. package/src/core/installers/ClientInstaller.ts +423 -0
  96. package/src/core/installers/CommandInstaller.ts +185 -0
  97. package/src/core/installers/GeneralInstaller.ts +89 -0
  98. package/src/core/installers/InstallerFactory.ts +109 -0
  99. package/src/core/installers/NpmInstaller.ts +128 -0
  100. package/src/core/installers/PipInstaller.ts +121 -0
  101. package/src/core/installers/RequirementInstaller.ts +38 -0
  102. package/src/core/installers/index.ts +9 -0
  103. package/src/core/types.ts +163 -0
  104. package/src/index.ts +44 -0
  105. package/src/services/InstallRequestValidator.ts +112 -0
  106. package/src/services/ServerService.ts +181 -0
  107. package/src/utils/UpdateCheckTracker.ts +86 -0
  108. package/src/utils/clientUtils.ts +112 -0
  109. package/src/utils/feedUtils.ts +31 -0
  110. package/src/utils/githubAuth.ts +142 -0
  111. package/src/utils/logger.ts +101 -0
  112. package/src/utils/osUtils.ts +250 -0
  113. package/src/web/public/css/modal.css +250 -0
  114. package/src/web/public/css/notifications.css +70 -0
  115. package/src/web/public/index.html +157 -0
  116. package/src/web/public/js/api.js +213 -0
  117. package/src/web/public/js/modal.js +572 -0
  118. package/src/web/public/js/notifications.js +99 -0
  119. package/src/web/public/js/serverCategoryDetails.js +210 -0
  120. package/src/web/public/js/serverCategoryList.js +82 -0
  121. package/src/web/public/modal.html +61 -0
  122. package/src/web/public/styles.css +155 -0
  123. package/src/web/server.ts +195 -0
  124. package/tsconfig.json +18 -0
package/package.json ADDED
@@ -0,0 +1,53 @@
1
+ {
2
+ "name": "imcp",
3
+ "version": "0.0.1",
4
+ "description": "Node.js SDK for Model Context Protocol (MCP)",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "bin": {
8
+ "imcp": "./dist/cli/index.js"
9
+ },
10
+ "scripts": {
11
+ "build": "tsc && npm run copy-public && npm run copy-feeds",
12
+ "dev": "tsc -w",
13
+ "start": "node dist/web/server.js",
14
+ "dev:server": "ts-node-dev --respawn --transpile-only src/cli/index.ts start",
15
+ "test": "jest",
16
+ "lint": "eslint src --ext .ts",
17
+ "format": "prettier --write \"src/**/*.ts\"",
18
+ "copy-public": "xcopy /E /I /Y src\\web\\public dist\\web\\public",
19
+ "copy-feeds": "xcopy /E /I /Y src\\feeds dist\\feeds"
20
+ },
21
+ "keywords": [
22
+ "mcp",
23
+ "sdk",
24
+ "cli"
25
+ ],
26
+ "author": "",
27
+ "license": "MIT",
28
+ "dependencies": {
29
+ "axios": "^1.6.2",
30
+ "commander": "^11.1.0",
31
+ "express": "^4.18.2",
32
+ "extract-zip": "^2.0.1",
33
+ "unzipper": "^0.10.14"
34
+ },
35
+ "devDependencies": {
36
+ "@types/express": "^4.17.21",
37
+ "@types/jest": "^29.5.11",
38
+ "@types/node": "^20.10.5",
39
+ "@typescript-eslint/eslint-plugin": "^6.15.0",
40
+ "@typescript-eslint/parser": "^6.15.0",
41
+ "eslint": "^8.56.0",
42
+ "jest": "^29.7.0",
43
+ "prettier": "^3.1.1",
44
+ "ts-jest": "^29.1.1",
45
+ "ts-node": "^10.9.2",
46
+ "ts-node-dev": "^2.0.0",
47
+ "typescript": "^5.3.3"
48
+ },
49
+ "publishConfig": {
50
+ "access": "public"
51
+ },
52
+ "type": "module"
53
+ }
@@ -0,0 +1,140 @@
1
+ import { Command } from 'commander';
2
+ import { serverService } from '../../services/ServerService.js';
3
+ import { Logger } from '../../utils/logger.js';
4
+ import { hasLocalFeeds } from '../../utils/feedUtils.js';
5
+ import { ServerInstallOptions } from '../../core/types.js';
6
+ import { SUPPORTED_CLIENT_NAMES } from '../../core/constants.js';
7
+
8
+ export function createInstallCommand(): Command {
9
+ return new Command('install')
10
+ .description('Install specific MCP servers')
11
+ .addHelpText('after', `
12
+ Examples:
13
+ # Install a server
14
+ $ imcp install --category ai-coder-tools --name github-tools
15
+
16
+ # Install with specific client targets (semicolon separated)
17
+ $ imcp install --category ai-coder-tools --name github-tools --clients "MSRooCode;GithubCopilot"
18
+
19
+ # Install with environment variables
20
+ $ imcp install --category ai-coder-tools --name github-tools --envs "GITHUB_TOKEN=abc123;API_KEY=xyz789"
21
+ `)
22
+ .requiredOption(
23
+ '--category <category>',
24
+ 'Server category'
25
+ )
26
+ .requiredOption(
27
+ '--name <name>',
28
+ 'Server name to install'
29
+ )
30
+ .option(
31
+ '--force',
32
+ 'Force installation even if server already exists',
33
+ false
34
+ )
35
+ .option(
36
+ '--clients <clients>',
37
+ 'Target clients (semicolon separated). Supported values: Cline, MSRooCode, GithubCopilot. If not specified, installs for all clients'
38
+ )
39
+ .option(
40
+ '--envs <envs>',
41
+ 'Environment variables (semicolon separated key=value pairs)'
42
+ )
43
+ .action(async (options: {
44
+ category: string;
45
+ name: string;
46
+ force: boolean;
47
+ clients?: string;
48
+ envs?: string;
49
+ verbose?: boolean;
50
+ }) => {
51
+ try {
52
+ // Check for local feeds existence at the start
53
+ const feedsExist = await hasLocalFeeds();
54
+ if (!feedsExist) {
55
+ Logger.log('Local feeds not found, syncing from remote...');
56
+ await serverService.syncFeeds();
57
+ }
58
+
59
+ const { category, name, verbose, force, clients, envs } = options;
60
+
61
+ Logger.debug(`Install options: ${JSON.stringify({ category, name, force, verbose, clients, envs })}`);
62
+
63
+ const serverName = name.trim();
64
+ Logger.debug(`Server name: ${serverName}`);
65
+
66
+ if (!await serverService.validateServerName(category, serverName)) {
67
+ Logger.error('Invalid server name or category provided', {
68
+ category,
69
+ serverName
70
+ });
71
+ process.exit(1);
72
+ }
73
+
74
+ // Parse and validate clients
75
+ const parsedClients = clients ? clients.split(';')
76
+ .map((c: string) => c.trim())
77
+ .filter(Boolean)
78
+ .map((c: string) => {
79
+ const clientName = c.toLowerCase();
80
+ const validClient = SUPPORTED_CLIENT_NAMES.find((name: string) => name.toLowerCase() === clientName);
81
+ if (!validClient) {
82
+ Logger.error(`Invalid client name: ${c}`);
83
+ return null;
84
+ }
85
+ return validClient;
86
+ })
87
+ .filter((c: string | null): c is string => c !== null) : undefined;
88
+
89
+ if (parsedClients && parsedClients.length > 0) {
90
+ Logger.debug(`Target clients: ${JSON.stringify(parsedClients)}`);
91
+ }
92
+
93
+ // Parse environment variables
94
+ const parsedEnvs: Record<string, string> = {};
95
+ if (envs) {
96
+ const pairs = envs.split(';');
97
+ for (const pair of pairs) {
98
+ const [key, value] = pair.split('=').map((s: string) => s.trim());
99
+ if (key && value) {
100
+ parsedEnvs[key] = value;
101
+ } else {
102
+ Logger.error(`Invalid environment variable format: ${pair}`);
103
+ }
104
+ }
105
+ }
106
+
107
+ if (Object.keys(parsedEnvs).length > 0) {
108
+ Logger.debug(`Environment variables: ${JSON.stringify(parsedEnvs)}`);
109
+ }
110
+
111
+ Logger.log(`Installing server: ${serverName}`);
112
+
113
+ const installOptions: ServerInstallOptions = {
114
+ force: options.force,
115
+ ...(parsedClients?.length && { targetClients: parsedClients }),
116
+ ...(Object.keys(parsedEnvs).length > 0 && { env: parsedEnvs })
117
+ };
118
+
119
+ const results = [await serverService.installMcpServer(category, serverName, installOptions)];
120
+
121
+ const { success, messages } = serverService.formatOperationResults(results);
122
+
123
+ messages.forEach((message: string) => {
124
+ if (success) {
125
+ Logger.log(`✓ ${message}`);
126
+ } else {
127
+ Logger.error(`✗ ${message}`);
128
+ }
129
+ });
130
+
131
+ if (!success) {
132
+ process.exit(1);
133
+ }
134
+ } catch (error: unknown) {
135
+ const message = error instanceof Error ? error.message : 'Unknown error';
136
+ Logger.error('Installation failed:', message);
137
+ process.exit(1);
138
+ }
139
+ });
140
+ }
@@ -0,0 +1,112 @@
1
+ import { Command } from 'commander';
2
+ import fs from 'fs/promises';
3
+ import path from 'path';
4
+ import { LOCAL_FEEDS_DIR } from '../../core/constants.js';
5
+ import { mcpManager } from '../../core/MCPManager.js';
6
+ import { Logger } from '../../utils/logger.js';
7
+
8
+ interface SimplifiedServer {
9
+ name: string;
10
+ description: string;
11
+ }
12
+
13
+ interface SimplifiedFeed {
14
+ name: string;
15
+ displayName: string;
16
+ description: string;
17
+ mcpServers: SimplifiedServer[];
18
+ }
19
+
20
+ export function createListCommand(): Command {
21
+ return new Command('list')
22
+ .description('List all available MCP servers from feeds')
23
+ .option('--pull', 'Sync with remote feeds before listing')
24
+ .action(async (options) => {
25
+ try {
26
+ Logger.debug({
27
+ action: 'list_command_started',
28
+ options
29
+ });
30
+
31
+ // If sync flag is provided, try to sync first
32
+ if (options.pull) {
33
+ try {
34
+ await mcpManager.syncFeeds();
35
+ } catch (syncError) {
36
+ Logger.error('Failed to sync feeds, falling back to local feeds', syncError);
37
+ }
38
+ }
39
+
40
+ Logger.debug({
41
+ action: 'ensuring_feeds_directory',
42
+ path: LOCAL_FEEDS_DIR
43
+ });
44
+
45
+ // Ensure feeds directory exists
46
+ await fs.mkdir(LOCAL_FEEDS_DIR, { recursive: true });
47
+
48
+ // Read all json files from feeds directory
49
+ Logger.debug('Reading feed files from directory...');
50
+ const files = await fs.readdir(LOCAL_FEEDS_DIR);
51
+ const jsonFiles = files.filter(file => file.endsWith('.json'));
52
+
53
+ Logger.debug({
54
+ action: 'found_feed_files',
55
+ count: jsonFiles.length,
56
+ files: jsonFiles
57
+ });
58
+
59
+ const feeds: SimplifiedFeed[] = [];
60
+
61
+ // Process each json file
62
+ for (const file of jsonFiles) {
63
+ Logger.debug(`Processing feed file: ${file}`);
64
+ try {
65
+ const filePath = path.join(LOCAL_FEEDS_DIR, file);
66
+ const content = await fs.readFile(filePath, 'utf8');
67
+ const feedConfig = JSON.parse(content);
68
+
69
+ Logger.debug({
70
+ action: 'processing_feed',
71
+ file,
72
+ feedName: feedConfig.name,
73
+ serverCount: feedConfig.mcpServers?.length ?? 0
74
+ });
75
+
76
+ // Extract only needed information
77
+ const simplifiedFeed: SimplifiedFeed = {
78
+ name: feedConfig.name,
79
+ displayName: feedConfig.displayName,
80
+ description: feedConfig.description,
81
+ mcpServers: feedConfig.mcpServers.map((server: any) => ({
82
+ name: server.name,
83
+ description: server.description
84
+ }))
85
+ };
86
+
87
+ feeds.push(simplifiedFeed);
88
+ Logger.debug(`Successfully processed feed: ${feedConfig.name}`);
89
+ } catch (error) {
90
+ Logger.error(`Failed to process feed file: ${file}`, error);
91
+ }
92
+ }
93
+
94
+ if (feeds.length === 0) {
95
+ Logger.log('No feeds found.');
96
+ return;
97
+ }
98
+
99
+ Logger.debug({
100
+ action: 'completed_processing',
101
+ totalFeeds: feeds.length,
102
+ totalServers: feeds.reduce((acc, feed) => acc + feed.mcpServers.length, 0)
103
+ });
104
+
105
+ // Output as formatted JSON
106
+ console.log(JSON.stringify(feeds, null, 2));
107
+ } catch (error) {
108
+ Logger.error('Failed to list servers', error);
109
+ process.exit(1);
110
+ }
111
+ });
112
+ }
@@ -0,0 +1,16 @@
1
+ import { Command } from 'commander';
2
+ import { serverService } from '../../services/ServerService.js';
3
+
4
+ export function createPullCommand(): Command {
5
+ return new Command('pull')
6
+ .description('Pull MCP server configurations from remote feed source')
7
+ .action(async () => {
8
+ try {
9
+ await serverService.syncFeeds();
10
+ } catch (error) {
11
+ const message = error instanceof Error ? error.message : 'Unknown error';
12
+ console.error('Error syncing configurations:', message);
13
+ process.exit(1);
14
+ }
15
+ });
16
+ }
@@ -0,0 +1,37 @@
1
+ import { Command } from 'commander';
2
+ import { startWebServer } from '../../web/server.js';
3
+ import { mcpManager } from '../../core/MCPManager.js';
4
+ import { checkGithubAuth } from '../../utils/githubAuth.js';
5
+ import { Logger } from '../../utils/logger.js';
6
+
7
+ export function createServeCommand(): Command {
8
+ return new Command('serve')
9
+ .description('Serve local web interface')
10
+ .option('-p, --port <port>', 'Port to run the server on', '3000')
11
+ .action(async (options) => {
12
+ try {
13
+ // Sync feeds before start the local UI
14
+ await mcpManager.syncFeeds();
15
+
16
+ // Ensure MCP manager is initialized before starting the web server
17
+ await mcpManager.initialize();
18
+
19
+ const port = parseInt(options.port, 10);
20
+ if (isNaN(port) || port < 1 || port > 65535) {
21
+ throw new Error('Invalid port number');
22
+ }
23
+
24
+ await startWebServer(port);
25
+
26
+ // The server is running, keep the process alive
27
+ process.on('SIGINT', () => {
28
+ console.log('\nShutting down server...');
29
+ process.exit(0);
30
+ });
31
+ } catch (error) {
32
+ const message = error instanceof Error ? error.message : 'Unknown error';
33
+ console.error('Failed to start web server:', message);
34
+ process.exit(1);
35
+ }
36
+ });
37
+ }
@@ -0,0 +1,54 @@
1
+ import { Command } from 'commander';
2
+ import { serverService } from '../../services/ServerService.js';
3
+
4
+ export function createUninstallCommand(): Command {
5
+ return new Command('uninstall')
6
+ .description('Uninstall specific MCP servers')
7
+ .requiredOption(
8
+ '--category <category>',
9
+ '--names <names>',
10
+ 'Server names (semicolon separated)'
11
+ )
12
+ .option(
13
+ '--remove-data',
14
+ 'Remove all associated data',
15
+ false
16
+ )
17
+ .action(async (options) => {
18
+ try {
19
+ const serverNames = options.names.split(';').map((name: string) => name.trim());
20
+
21
+ if (!serverService.validateServerName(options.category, serverNames)) {
22
+ console.error('Invalid server names provided');
23
+ process.exit(1);
24
+ }
25
+
26
+ console.log(`Uninstalling servers: ${serverNames.join(', ')}`);
27
+
28
+ const results = await Promise.all(
29
+ serverNames.map((serverName: string) =>
30
+ serverService.uninstallMcpServer(options.category, serverName, {
31
+ removeData: options.removeData,
32
+ })
33
+ )
34
+ );
35
+
36
+ const { success, messages } = serverService.formatOperationResults(results);
37
+ messages.forEach(message => {
38
+ if (success) {
39
+ console.log(`✓ ${message}`);
40
+ } else {
41
+ console.error(`✗ ${message}`);
42
+ }
43
+ });
44
+
45
+ if (!success) {
46
+ process.exit(1);
47
+ }
48
+ } catch (error) {
49
+ const message = error instanceof Error ? error.message : 'Unknown error';
50
+ console.error('Uninstallation failed:', message);
51
+ process.exit(1);
52
+ }
53
+ });
54
+ }
@@ -0,0 +1,127 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { Command } from 'commander';
4
+ import { createServeCommand } from './commands/serve.js';
5
+ import { createListCommand } from './commands/list.js';
6
+ import { createInstallCommand } from './commands/install.js';
7
+ import { createUninstallCommand } from './commands/uninstall.js';
8
+ import { createPullCommand } from './commands/pull.js';
9
+ import { mcpManager } from '../core/MCPManager.js';
10
+ import { Logger } from '../utils/logger.js';
11
+ import axios from 'axios';
12
+ import path from 'path';
13
+ import { fileURLToPath } from 'url';
14
+ import fs from 'fs';
15
+
16
+ // Custom error interface for Commander.js errors
17
+ // ANSI color codes
18
+ const COLORS = {
19
+ reset: '\x1b[0m',
20
+ yellow: '\x1b[33m'
21
+ };
22
+
23
+ interface CommanderError extends Error {
24
+ code?: string;
25
+ }
26
+
27
+ async function main(): Promise<void> {
28
+ // Initialize the MCP manager
29
+ await mcpManager.initialize();
30
+
31
+ const program = new Command();
32
+ program
33
+ .name('imcp')
34
+ .description('IMCP (Install Model Context Protocol) CLI')
35
+ .version('0.0.1')
36
+ .option('--verbose', 'Show detailed logs for all commands');
37
+
38
+ // Parse global options first
39
+ program.parseOptions(process.argv);
40
+ const opts = program.opts();
41
+ Logger.setVerbose(!!opts.verbose);
42
+
43
+ // Add all commands
44
+ program.addCommand(createServeCommand());
45
+ program.addCommand(createListCommand());
46
+ program.addCommand(createInstallCommand());
47
+ // program.addCommand(createUninstallCommand());
48
+ program.addCommand(createPullCommand());
49
+
50
+ // Error handling for the entire CLI
51
+ program.exitOverride();
52
+
53
+ // Check for updates
54
+ await checkForUpdates();
55
+
56
+ try {
57
+ await program.parseAsync(process.argv);
58
+ } catch (error) {
59
+ const commanderError = error as CommanderError;
60
+
61
+ if (commanderError.code === 'commander.help') {
62
+ // Help was displayed, exit normally
63
+ process.exit(0);
64
+ } else if (commanderError.code === 'commander.version') {
65
+ // Version was displayed, exit normally
66
+ process.exit(0);
67
+ } else {
68
+ console.error('Error:', commanderError.message || 'An unknown error occurred');
69
+ process.exit(1);
70
+ }
71
+ }
72
+ }
73
+
74
+ // Handle unhandled promise rejections
75
+ process.on('unhandledRejection', (error: unknown) => {
76
+ if (error instanceof Error) {
77
+ console.error('Unhandled promise rejection:', error.message);
78
+ } else {
79
+ console.error('Unhandled promise rejection:', error);
80
+ }
81
+ process.exit(1);
82
+ });
83
+
84
+ /**
85
+ * Check if there's a newer version of the package available
86
+ */
87
+ async function checkForUpdates(): Promise<void> {
88
+ try {
89
+ // Get the current package version
90
+ const __filename = fileURLToPath(import.meta.url);
91
+ const __dirname = path.dirname(__filename);
92
+ const packagePath = path.resolve(__dirname, '../../package.json');
93
+ const packageJson = JSON.parse(fs.readFileSync(packagePath, 'utf8'));
94
+ const currentVersion = packageJson.name && packageJson.version ? packageJson.version : '0.0.0';
95
+ const packageName = packageJson.name || 'imcp';
96
+
97
+ try {
98
+ // Get the latest version from npm registry (only for published packages)
99
+ const npmResponse = await axios.get(`https://registry.npmjs.org/${packageName}`);
100
+
101
+ if (npmResponse.data && npmResponse.data['dist-tags'] && npmResponse.data['dist-tags'].latest) {
102
+ const latestVersion = npmResponse.data['dist-tags'].latest;
103
+
104
+ if (latestVersion && latestVersion !== currentVersion) {
105
+ console.log(`${COLORS.yellow}Update available for ${packageName}: ${currentVersion} → ${latestVersion}${COLORS.reset}`);
106
+ console.log(`${COLORS.yellow}Run \`npm install -g ${packageName}@latest\` to update${COLORS.reset}`);
107
+ }
108
+ }
109
+ } catch (npmError) {
110
+ // Log the npm error
111
+ Logger.debug(`Failed to check npm registry: ${npmError instanceof Error ? npmError.message : String(npmError)}`);
112
+ }
113
+ } catch (error) {
114
+ // Silently fail - don't interrupt the command if update check fails
115
+ Logger.debug(`Failed to check for updates: ${error instanceof Error ? error.message : String(error)}`);
116
+ }
117
+ }
118
+
119
+ // Start the CLI
120
+ main().catch((error: unknown) => {
121
+ if (error instanceof Error) {
122
+ console.error('Fatal error:', error.message);
123
+ } else {
124
+ console.error('Fatal error:', error);
125
+ }
126
+ process.exit(1);
127
+ });