@dypai-ai/mcp 1.5.26 → 1.5.27
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/package.json +1 -1
- package/src/auto-update.js +14 -59
package/package.json
CHANGED
package/src/auto-update.js
CHANGED
|
@@ -1,13 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Self-update for @dypai-ai/mcp.
|
|
3
3
|
*
|
|
4
|
-
* On startup, checks the npm registry for a newer version. If found, performs
|
|
4
|
+
* On every startup, checks the npm registry for a newer version. If found, performs
|
|
5
5
|
* the appropriate update (clear npx cache or `npm install -g`) and exits with
|
|
6
6
|
* code 0 so the host (Cursor / Claude / Trae / VSCode) re-spawns the process
|
|
7
7
|
* with the freshly installed version.
|
|
8
8
|
*
|
|
9
|
-
* Throttled to one check every 6h to avoid hammering the registry.
|
|
10
|
-
*
|
|
11
9
|
* Disable with: DYPAI_NO_AUTOUPDATE=1
|
|
12
10
|
*/
|
|
13
11
|
|
|
@@ -21,13 +19,7 @@ const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
|
21
19
|
const PKG_PATH = join(__dirname, "..", "package.json");
|
|
22
20
|
const PKG_NAME = "@dypai-ai/mcp";
|
|
23
21
|
const REGISTRY_URL = `https://registry.npmjs.org/${PKG_NAME}/latest`;
|
|
24
|
-
// Dist-tags endpoint is tiny (<200B) — used to check if there's a CRITICAL
|
|
25
|
-
// release the user must upgrade to immediately, bypassing the 6h throttle.
|
|
26
|
-
// To mark a version as critical after publish:
|
|
27
|
-
// npm dist-tag add @dypai-ai/mcp@1.4.5 critical
|
|
28
|
-
const DIST_TAGS_URL = `https://registry.npmjs.org/-/package/${PKG_NAME}/dist-tags`;
|
|
29
22
|
const CHECK_TIMEOUT_MS = 2000;
|
|
30
|
-
const THROTTLE_HOURS = 6;
|
|
31
23
|
const STATE_FILE = join(tmpdir(), "dypai-mcp-update-state.json");
|
|
32
24
|
|
|
33
25
|
function log(msg) {
|
|
@@ -73,32 +65,6 @@ async function fetchLatestManifest() {
|
|
|
73
65
|
}
|
|
74
66
|
}
|
|
75
67
|
|
|
76
|
-
/**
|
|
77
|
-
* Fetch the `critical` dist-tag (if published). Used to bypass the 6h throttle
|
|
78
|
-
* when a release is important enough that users must upgrade on next spawn.
|
|
79
|
-
*
|
|
80
|
-
* Returns the critical version string (e.g. "1.4.5") or null if no critical
|
|
81
|
-
* tag is set, the registry is unreachable, or the response is malformed.
|
|
82
|
-
*
|
|
83
|
-
* Cost: one tiny JSON fetch (~200 bytes) per spawn. Adds ~50-150ms to startup
|
|
84
|
-
* but runs in parallel with the rest of the MCP init, so wall-clock impact is
|
|
85
|
-
* usually zero.
|
|
86
|
-
*/
|
|
87
|
-
async function fetchCriticalVersion() {
|
|
88
|
-
const ctrl = new AbortController();
|
|
89
|
-
const timer = setTimeout(() => ctrl.abort(), CHECK_TIMEOUT_MS);
|
|
90
|
-
try {
|
|
91
|
-
const res = await fetch(DIST_TAGS_URL, { signal: ctrl.signal });
|
|
92
|
-
if (!res.ok) return null;
|
|
93
|
-
const tags = await res.json();
|
|
94
|
-
return typeof tags?.critical === "string" ? tags.critical : null;
|
|
95
|
-
} catch {
|
|
96
|
-
return null;
|
|
97
|
-
} finally {
|
|
98
|
-
clearTimeout(timer);
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
|
|
102
68
|
/**
|
|
103
69
|
* After npm publish there's a 30s–2min window where the registry knows the
|
|
104
70
|
* version but the tarball is not yet replicated across the CDN. If we clear
|
|
@@ -170,37 +136,21 @@ function installGlobalLatest() {
|
|
|
170
136
|
* Main entry point — call once at startup.
|
|
171
137
|
* Returns quickly. Exits the process if an update was applied.
|
|
172
138
|
*/
|
|
173
|
-
export async function checkForUpdates(
|
|
139
|
+
export async function checkForUpdates() {
|
|
174
140
|
if (process.env.DYPAI_NO_AUTOUPDATE === "1") return { skipped: "disabled" };
|
|
175
141
|
|
|
176
142
|
const current = getCurrentVersion();
|
|
177
143
|
if (!current) return { skipped: "no current version" };
|
|
178
144
|
|
|
179
|
-
// ── Critical release check (bypasses the 6h throttle) ────────────────────
|
|
180
|
-
// If an ops person has run `npm dist-tag add @dypai-ai/mcp@X.Y.Z critical`,
|
|
181
|
-
// every spawn picks that up and forces an upgrade regardless of when the
|
|
182
|
-
// last normal check ran. Used for security / data-loss bug fixes where
|
|
183
|
-
// 6-24h propagation is too slow.
|
|
184
|
-
const criticalVersion = await fetchCriticalVersion();
|
|
185
|
-
const hasCritical = criticalVersion && compareVersions(criticalVersion, current) > 0;
|
|
186
|
-
if (hasCritical) {
|
|
187
|
-
log(`CRITICAL update required: ${current} → ${criticalVersion} (bypassing throttle)`);
|
|
188
|
-
force = true;
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
// Throttle (skipped when force or critical)
|
|
192
|
-
if (!force) {
|
|
193
|
-
const state = readState();
|
|
194
|
-
if (state.lastCheckAt) {
|
|
195
|
-
const hoursAgo = (Date.now() - state.lastCheckAt) / 3_600_000;
|
|
196
|
-
if (hoursAgo < THROTTLE_HOURS) return { skipped: "throttled" };
|
|
197
|
-
}
|
|
198
|
-
}
|
|
199
|
-
|
|
200
145
|
const manifest = await fetchLatestManifest();
|
|
201
146
|
const latest = manifest?.version || null;
|
|
202
147
|
const tarballUrl = manifest?.dist?.tarball || null;
|
|
203
|
-
writeState({
|
|
148
|
+
writeState({
|
|
149
|
+
...readState(),
|
|
150
|
+
lastCheckAt: Date.now(),
|
|
151
|
+
lastSeenLatest: latest,
|
|
152
|
+
current,
|
|
153
|
+
});
|
|
204
154
|
|
|
205
155
|
if (!latest) return { skipped: "registry unreachable" };
|
|
206
156
|
if (compareVersions(latest, current) <= 0) return { uptodate: true, current };
|
|
@@ -213,7 +163,7 @@ export async function checkForUpdates({ force = false } = {}) {
|
|
|
213
163
|
// If we clear the cache + exit during that window, next spawn fails.
|
|
214
164
|
const ready = await isTarballReady(tarballUrl);
|
|
215
165
|
if (!ready) {
|
|
216
|
-
log(`new version ${latest} not yet downloadable from CDN; will retry
|
|
166
|
+
log(`new version ${latest} not yet downloadable from CDN; will retry on next spawn`);
|
|
217
167
|
return { skipped: "tarball not ready" };
|
|
218
168
|
}
|
|
219
169
|
|
|
@@ -223,6 +173,11 @@ export async function checkForUpdates({ force = false } = {}) {
|
|
|
223
173
|
if (method === "npx") {
|
|
224
174
|
log(`tarball verified — clearing npx cache so the next spawn pulls ${PKG_NAME}@${latest}`);
|
|
225
175
|
updated = clearNpxCacheForPackage();
|
|
176
|
+
// Even if no cached dir matched, exit so npx re-resolves @latest on respawn.
|
|
177
|
+
if (!updated) {
|
|
178
|
+
log("no npx cache entry found; exiting anyway so the host re-resolves @latest");
|
|
179
|
+
updated = true;
|
|
180
|
+
}
|
|
226
181
|
} else if (method === "global") {
|
|
227
182
|
log(`tarball verified — running: npm install -g ${PKG_NAME}@latest`);
|
|
228
183
|
updated = installGlobalLatest();
|