@morphllm/morphmcp 0.8.35 → 0.8.37

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 (2) hide show
  1. package/dist/index.js +142 -0
  2. package/package.json +3 -2
package/dist/index.js CHANGED
@@ -6,10 +6,12 @@ import fs from "fs/promises";
6
6
  import path from "path";
7
7
  import os from 'os';
8
8
  import { randomBytes } from 'crypto';
9
+ import { spawn } from 'child_process';
9
10
  import { z } from "zod";
10
11
  import { zodToJsonSchema } from "zod-to-json-schema";
11
12
  import { createTwoFilesPatch } from 'diff';
12
13
  import { minimatch } from 'minimatch';
14
+ import semver from 'semver';
13
15
  import { getValidRootDirectories } from './roots-utils.js';
14
16
  import { executeEditFile } from '@morphllm/morphsdk/tools/fastapply';
15
17
  import { runWarpGrep, LocalRipgrepProvider } from '@morphllm/morphsdk/tools/warp-grep';
@@ -72,6 +74,144 @@ if (args.length === 0 && !ENABLE_WORKSPACE_MODE) {
72
74
  console.error(" 3. Workspace mode (default behavior, set ENABLE_WORKSPACE_MODE=false to disable)");
73
75
  console.error("At least one directory must be provided by EITHER method for the server to operate.");
74
76
  }
77
+ // =============================================================================
78
+ // Auto-Update System
79
+ // Checks for SDK updates periodically and installs them automatically
80
+ // =============================================================================
81
+ const AUTO_UPDATE_INTERVAL_MS = parseInt(process.env.AUTO_UPDATE_INTERVAL_MS || '3600000', 10); // Default: 1 hour
82
+ const DISABLE_AUTO_UPDATE = process.env.DISABLE_AUTO_UPDATE === 'true';
83
+ // Get current installed version from package.json
84
+ async function getInstalledVersion(packageName) {
85
+ try {
86
+ // For @morphllm/morphsdk, check the node_modules
87
+ const packageJsonPath = path.join(path.dirname(new URL(import.meta.url).pathname), '..', 'node_modules', ...packageName.split('/'), 'package.json');
88
+ const content = await fs.readFile(packageJsonPath, 'utf-8');
89
+ const pkg = JSON.parse(content);
90
+ return pkg.version || null;
91
+ }
92
+ catch {
93
+ // Try alternative path (when running from dist)
94
+ try {
95
+ const altPath = path.join(path.dirname(new URL(import.meta.url).pathname), 'node_modules', ...packageName.split('/'), 'package.json');
96
+ const content = await fs.readFile(altPath, 'utf-8');
97
+ const pkg = JSON.parse(content);
98
+ return pkg.version || null;
99
+ }
100
+ catch {
101
+ return null;
102
+ }
103
+ }
104
+ }
105
+ // Fetch latest version from npm registry
106
+ async function getLatestVersion(packageName) {
107
+ try {
108
+ const response = await axios.get(`https://registry.npmjs.org/${packageName}/latest`, { timeout: 10000 });
109
+ return response.data?.version || null;
110
+ }
111
+ catch {
112
+ return null;
113
+ }
114
+ }
115
+ // Check if update is available for a package
116
+ async function checkPackageUpdate(packageName) {
117
+ const currentVersion = await getInstalledVersion(packageName);
118
+ const latestVersion = await getLatestVersion(packageName);
119
+ let updateAvailable = false;
120
+ if (currentVersion && latestVersion) {
121
+ try {
122
+ updateAvailable = semver.lt(currentVersion, latestVersion);
123
+ }
124
+ catch {
125
+ // Invalid semver, skip
126
+ }
127
+ }
128
+ return {
129
+ name: packageName,
130
+ currentVersion: currentVersion || 'unknown',
131
+ latestVersion,
132
+ updateAvailable,
133
+ };
134
+ }
135
+ // Run npm/bun update and wait for completion
136
+ function runPackageUpdate(packageName) {
137
+ return new Promise((resolve) => {
138
+ // Determine package manager (prefer bun if available)
139
+ const packageManager = process.env.npm_execpath?.includes('bun') ? 'bun' : 'npm';
140
+ const args = packageManager === 'bun'
141
+ ? ['add', packageName + '@latest']
142
+ : ['install', packageName + '@latest'];
143
+ const packageDir = path.dirname(new URL(import.meta.url).pathname);
144
+ const child = spawn(packageManager, args, {
145
+ cwd: packageDir,
146
+ stdio: 'pipe', // Capture output for debugging
147
+ env: { ...process.env, npm_config_fund: 'false', npm_config_audit: 'false' }, // Skip fund/audit for speed
148
+ });
149
+ let stderr = '';
150
+ child.stderr?.on('data', (data) => { stderr += data.toString(); });
151
+ child.on('error', (err) => {
152
+ console.error(`Update error: ${err.message}`);
153
+ resolve(false);
154
+ });
155
+ child.on('close', (code) => {
156
+ if (code !== 0 && stderr) {
157
+ console.error(`Update failed: ${stderr.slice(0, 200)}`);
158
+ }
159
+ resolve(code === 0);
160
+ });
161
+ // Timeout after 60 seconds
162
+ setTimeout(() => {
163
+ child.kill();
164
+ resolve(false);
165
+ }, 60000);
166
+ });
167
+ }
168
+ // Main auto-update check function
169
+ async function checkAndUpdatePackages() {
170
+ const packagesToCheck = [
171
+ '@morphllm/morphsdk',
172
+ '@morphllm/morphmcp',
173
+ ];
174
+ for (const packageName of packagesToCheck) {
175
+ try {
176
+ const info = await checkPackageUpdate(packageName);
177
+ if (info.updateAvailable) {
178
+ console.error(`🔄 Update available for ${packageName}: ${info.currentVersion} → ${info.latestVersion}`);
179
+ console.error(`📦 Installing ${packageName}@${info.latestVersion}...`);
180
+ // Attempt to update and wait for completion
181
+ const updateSucceeded = await runPackageUpdate(packageName);
182
+ if (updateSucceeded) {
183
+ console.error(`✅ Updated ${packageName} to ${info.latestVersion} (will take effect on next restart)`);
184
+ }
185
+ else {
186
+ console.error(`⚠️ Failed to update ${packageName}`);
187
+ }
188
+ }
189
+ }
190
+ catch (error) {
191
+ // Silently ignore update check failures - don't disrupt the server
192
+ }
193
+ }
194
+ }
195
+ // Start auto-update interval
196
+ let autoUpdateInterval = null;
197
+ function startAutoUpdate() {
198
+ if (DISABLE_AUTO_UPDATE) {
199
+ console.error('Auto-update disabled via DISABLE_AUTO_UPDATE=true');
200
+ return;
201
+ }
202
+ console.error(`Auto-update enabled: checking every ${Math.round(AUTO_UPDATE_INTERVAL_MS / 60000)} minutes`);
203
+ // Check immediately on startup (after a short delay to not block initialization)
204
+ setTimeout(() => {
205
+ checkAndUpdatePackages().catch(() => { });
206
+ }, 5000);
207
+ // Then check periodically
208
+ autoUpdateInterval = setInterval(() => {
209
+ checkAndUpdatePackages().catch(() => { });
210
+ }, AUTO_UPDATE_INTERVAL_MS);
211
+ // Don't keep process alive just for updates
212
+ autoUpdateInterval.unref();
213
+ }
214
+ // =============================================================================
75
215
  // Normalize all paths consistently
76
216
  function normalizePath(p) {
77
217
  return path.normalize(p);
@@ -1077,6 +1217,8 @@ async function runServer() {
1077
1217
  if (allowedDirectories.length === 0) {
1078
1218
  console.error("Started without allowed directories - waiting for client to provide roots via MCP protocol");
1079
1219
  }
1220
+ // Start auto-update system
1221
+ startAutoUpdate();
1080
1222
  }
1081
1223
  runServer().catch((error) => {
1082
1224
  console.error("Fatal error running server:", error);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@morphllm/morphmcp",
3
- "version": "0.8.35",
3
+ "version": "0.8.37",
4
4
  "description": "Fast & accurate MCP server with AI-powered file editing and intelligent code search. Prevents context pollution and saves time for a better user experience.",
5
5
  "license": "MIT",
6
6
  "author": "Morph (https://morphllm.com)",
@@ -33,9 +33,10 @@
33
33
  "test": "jest --config=jest.config.cjs --coverage"
34
34
  },
35
35
  "dependencies": {
36
+ "@google/generative-ai": "^0.21.0",
36
37
  "@modelcontextprotocol/sdk": "^1.12.3",
37
- "@vscode/ripgrep": "^1.15.14",
38
38
  "@morphllm/morphsdk": "*",
39
+ "@vscode/ripgrep": "^1.15.14",
39
40
  "axios": "^1.6.0",
40
41
  "chalk": "^5.3.0",
41
42
  "diff": "^5.1.0",