@syke1/mcp-server 1.8.0 → 1.8.2
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/dist/index.js +24 -6
- package/dist/web/public/app.js +29 -0
- package/dist/web/server.js +51 -6
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -76,7 +76,7 @@ function resolveFilePath(fileArg, projectRoot, sourceDir) {
|
|
|
76
76
|
// License state — set at startup
|
|
77
77
|
let licenseStatus = { plan: "free", source: "default" };
|
|
78
78
|
// Free tier limits
|
|
79
|
-
const FREE_MAX_FILES =
|
|
79
|
+
const FREE_MAX_FILES = 200;
|
|
80
80
|
function isPro() {
|
|
81
81
|
if (!(0, validator_1._verifyStatus)(licenseStatus)) {
|
|
82
82
|
licenseStatus = { plan: "free", source: "default" };
|
|
@@ -103,7 +103,7 @@ function getMaxFiles() {
|
|
|
103
103
|
}
|
|
104
104
|
/**
|
|
105
105
|
* Check if a resolved file path is within the free tier limit.
|
|
106
|
-
* Free set = first
|
|
106
|
+
* Free set = first 200 files sorted alphabetically by relative path.
|
|
107
107
|
*/
|
|
108
108
|
function isFileInFreeSet(resolvedPath, graph) {
|
|
109
109
|
if (isPro())
|
|
@@ -112,7 +112,7 @@ function isFileInFreeSet(resolvedPath, graph) {
|
|
|
112
112
|
const idx = allFiles.indexOf(resolvedPath);
|
|
113
113
|
return idx >= 0 && idx < FREE_MAX_FILES;
|
|
114
114
|
}
|
|
115
|
-
const PRO_UPGRADE_MSG = "This file exceeds the Free tier limit (
|
|
115
|
+
const PRO_UPGRADE_MSG = "This file exceeds the Free tier limit (200 files). Upgrade to Pro for unlimited analysis: https://syke.cloud/dashboard/";
|
|
116
116
|
function getProToolError(toolName) {
|
|
117
117
|
if (licenseStatus.error) {
|
|
118
118
|
return `${toolName}: ${licenseStatus.error}`;
|
|
@@ -147,7 +147,7 @@ async function main() {
|
|
|
147
147
|
};
|
|
148
148
|
process.on("SIGINT", shutdown);
|
|
149
149
|
process.on("SIGTERM", shutdown);
|
|
150
|
-
const server = new index_js_1.Server({ name: "syke", version: "1.8.
|
|
150
|
+
const server = new index_js_1.Server({ name: "syke", version: "1.8.2" }, { capabilities: { tools: {} } });
|
|
151
151
|
// List tools
|
|
152
152
|
server.setRequestHandler(types_js_1.ListToolsRequestSchema, async () => ({
|
|
153
153
|
tools: [
|
|
@@ -628,7 +628,7 @@ async function main() {
|
|
|
628
628
|
}
|
|
629
629
|
});
|
|
630
630
|
// Pre-warm the graph (skip if no project root — e.g. Smithery scan)
|
|
631
|
-
console.error(`[syke] Starting SYKE MCP Server v1.8.
|
|
631
|
+
console.error(`[syke] Starting SYKE MCP Server v1.8.2`);
|
|
632
632
|
console.error(`[syke] License: ${licenseStatus.plan.toUpperCase()} (${licenseStatus.source})`);
|
|
633
633
|
if (licenseStatus.expiresAt) {
|
|
634
634
|
console.error(`[syke] Expires: ${licenseStatus.expiresAt}`);
|
|
@@ -648,6 +648,24 @@ async function main() {
|
|
|
648
648
|
console.error(`[syke] Free tier: ${FREE_MAX_FILES} file limit, 3 tools (gate_build, check_safe, get_dependencies)`);
|
|
649
649
|
console.error(`[syke] Upgrade at https://syke.cloud/dashboard/`);
|
|
650
650
|
}
|
|
651
|
+
// Non-blocking update check
|
|
652
|
+
(async () => {
|
|
653
|
+
try {
|
|
654
|
+
const res = await fetch("https://registry.npmjs.org/@syke1/mcp-server", {
|
|
655
|
+
signal: AbortSignal.timeout(5000),
|
|
656
|
+
});
|
|
657
|
+
const data = await res.json();
|
|
658
|
+
const latest = data["dist-tags"]?.latest;
|
|
659
|
+
if (latest && latest !== "1.8.2") {
|
|
660
|
+
const [lM, lm, lp] = latest.split(".").map(Number);
|
|
661
|
+
const [cM, cm, cp] = [1, 8, 1];
|
|
662
|
+
if (lM > cM || (lM === cM && lm > cm) || (lM === cM && lm === cm && lp > cp)) {
|
|
663
|
+
console.error(`[syke] Update available: v${latest}. Run: npx @syke1/mcp-server@latest`);
|
|
664
|
+
}
|
|
665
|
+
}
|
|
666
|
+
}
|
|
667
|
+
catch { }
|
|
668
|
+
})();
|
|
651
669
|
let fileCache = null;
|
|
652
670
|
if (currentProjectRoot) {
|
|
653
671
|
const detectedLangs = (0, plugin_1.detectLanguages)(currentProjectRoot).map(p => p.name).join(", ") || "none";
|
|
@@ -798,7 +816,7 @@ main().catch((err) => {
|
|
|
798
816
|
* See: https://smithery.ai/docs/deploy#sandbox-server
|
|
799
817
|
*/
|
|
800
818
|
function createSandboxServer() {
|
|
801
|
-
const sandboxServer = new index_js_1.Server({ name: "syke", version: "1.8.
|
|
819
|
+
const sandboxServer = new index_js_1.Server({ name: "syke", version: "1.8.2" }, { capabilities: { tools: {} } });
|
|
802
820
|
sandboxServer.setRequestHandler(types_js_1.ListToolsRequestSchema, async () => ({
|
|
803
821
|
tools: [
|
|
804
822
|
{
|
package/dist/web/public/app.js
CHANGED
|
@@ -469,6 +469,7 @@ document.addEventListener("DOMContentLoaded", async () => {
|
|
|
469
469
|
setupFileTree();
|
|
470
470
|
initSSE();
|
|
471
471
|
startHealthCheck();
|
|
472
|
+
checkForUpdates();
|
|
472
473
|
});
|
|
473
474
|
|
|
474
475
|
// Periodic server health check (catches server down even without SSE)
|
|
@@ -3704,6 +3705,34 @@ async function updateBottomBar() {
|
|
|
3704
3705
|
}
|
|
3705
3706
|
}
|
|
3706
3707
|
|
|
3708
|
+
// ═══════════════════════════════════════════
|
|
3709
|
+
// UPDATE BANNER
|
|
3710
|
+
// ═══════════════════════════════════════════
|
|
3711
|
+
async function checkForUpdates() {
|
|
3712
|
+
try {
|
|
3713
|
+
const res = await fetch("/api/version", { signal: AbortSignal.timeout(8000) });
|
|
3714
|
+
const data = await res.json();
|
|
3715
|
+
if (!data.isOutdated) return;
|
|
3716
|
+
|
|
3717
|
+
// Remove existing banner if any
|
|
3718
|
+
const existing = document.getElementById("syke-update-banner");
|
|
3719
|
+
if (existing) existing.remove();
|
|
3720
|
+
|
|
3721
|
+
const banner = document.createElement("div");
|
|
3722
|
+
banner.id = "syke-update-banner";
|
|
3723
|
+
banner.style.cssText =
|
|
3724
|
+
"position:fixed;top:0;left:0;right:0;z-index:10000;padding:8px 16px;" +
|
|
3725
|
+
"background:linear-gradient(90deg,#0d1b2a,#1b2d45);border-bottom:1px solid rgba(0,212,255,0.3);" +
|
|
3726
|
+
"display:flex;align-items:center;justify-content:center;gap:12px;font-size:13px;color:#c8d6e5;font-family:Inter,sans-serif;";
|
|
3727
|
+
banner.innerHTML =
|
|
3728
|
+
'<span style="color:#00d4ff;font-weight:600;">Update available: v' + data.latestVersion + '</span>' +
|
|
3729
|
+
'<span style="color:#8899aa;">(current: v' + data.version + ')</span>' +
|
|
3730
|
+
'<code style="background:rgba(0,212,255,0.1);padding:2px 8px;border-radius:4px;font-size:12px;color:#00d4ff;">npx @syke1/mcp-server@latest</code>' +
|
|
3731
|
+
'<button onclick="this.parentElement.remove()" style="background:none;border:none;color:#556677;cursor:pointer;font-size:16px;margin-left:8px;" title="Dismiss">×</button>';
|
|
3732
|
+
document.body.prepend(banner);
|
|
3733
|
+
} catch {}
|
|
3734
|
+
}
|
|
3735
|
+
|
|
3707
3736
|
let browsePath = null; // current path in folder browser
|
|
3708
3737
|
|
|
3709
3738
|
async function browseDir(dirPath) {
|
package/dist/web/server.js
CHANGED
|
@@ -49,6 +49,17 @@ const analyze_impact_1 = require("../tools/analyze-impact");
|
|
|
49
49
|
const analyzer_1 = require("../ai/analyzer");
|
|
50
50
|
const realtime_analyzer_1 = require("../ai/realtime-analyzer");
|
|
51
51
|
const config_1 = require("../config");
|
|
52
|
+
// ── Semver comparison (returns >0 if a > b) ──
|
|
53
|
+
function compareVersions(a, b) {
|
|
54
|
+
const pa = a.split(".").map(Number);
|
|
55
|
+
const pb = b.split(".").map(Number);
|
|
56
|
+
for (let i = 0; i < 3; i++) {
|
|
57
|
+
const diff = (pa[i] || 0) - (pb[i] || 0);
|
|
58
|
+
if (diff !== 0)
|
|
59
|
+
return diff;
|
|
60
|
+
}
|
|
61
|
+
return 0;
|
|
62
|
+
}
|
|
52
63
|
// ── Real-time AI analysis toggle ──
|
|
53
64
|
let realtimeAIEnabled = true;
|
|
54
65
|
function resolveFilePath(fileArg, projectRoot, sourceDir) {
|
|
@@ -380,6 +391,40 @@ function createWebServer(getGraphFn, initialFileCache, switchProjectFn, getProje
|
|
|
380
391
|
wireFileCacheEvents(cache);
|
|
381
392
|
console.error(`[syke:sse] FileCache re-wired (${cache.size} files)`);
|
|
382
393
|
}
|
|
394
|
+
// ── npm version cache (24h TTL) ──
|
|
395
|
+
let npmVersionCache = null;
|
|
396
|
+
const NPM_CACHE_TTL = 24 * 60 * 60 * 1000; // 24 hours
|
|
397
|
+
async function fetchLatestNpmVersion() {
|
|
398
|
+
if (npmVersionCache && Date.now() - npmVersionCache.fetchedAt < NPM_CACHE_TTL) {
|
|
399
|
+
return npmVersionCache.version;
|
|
400
|
+
}
|
|
401
|
+
try {
|
|
402
|
+
const res = await fetch("https://registry.npmjs.org/@syke1/mcp-server", {
|
|
403
|
+
signal: AbortSignal.timeout(5000),
|
|
404
|
+
});
|
|
405
|
+
const data = await res.json();
|
|
406
|
+
const latest = data["dist-tags"]?.latest;
|
|
407
|
+
if (latest) {
|
|
408
|
+
npmVersionCache = { version: latest, fetchedAt: Date.now() };
|
|
409
|
+
return latest;
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
catch { }
|
|
413
|
+
return npmVersionCache?.version ?? null;
|
|
414
|
+
}
|
|
415
|
+
// GET /api/version — Lightweight version check endpoint
|
|
416
|
+
app.get("/api/version", async (_req, res) => {
|
|
417
|
+
let currentVersion = "unknown";
|
|
418
|
+
try {
|
|
419
|
+
const pkg = JSON.parse(fs.readFileSync(path.join(__dirname, "..", "package.json"), "utf-8"));
|
|
420
|
+
currentVersion = pkg.version || "unknown";
|
|
421
|
+
}
|
|
422
|
+
catch { }
|
|
423
|
+
const latestVersion = await fetchLatestNpmVersion();
|
|
424
|
+
const isOutdated = !!(latestVersion && currentVersion !== "unknown" && latestVersion !== currentVersion
|
|
425
|
+
&& compareVersions(latestVersion, currentVersion) > 0);
|
|
426
|
+
res.json({ version: currentVersion, latestVersion: latestVersion || currentVersion, isOutdated });
|
|
427
|
+
});
|
|
383
428
|
// GET /api/cache-status — Memory cache stats
|
|
384
429
|
app.get("/api/cache-status", (_req, res) => {
|
|
385
430
|
if (!currentFileCache) {
|
|
@@ -408,7 +453,7 @@ function createWebServer(getGraphFn, initialFileCache, switchProjectFn, getProje
|
|
|
408
453
|
app.get("/api/graph", (_req, res) => {
|
|
409
454
|
const graph = getGraphFn();
|
|
410
455
|
const isPro = isProPlan();
|
|
411
|
-
const FREE_GRAPH_LIMIT =
|
|
456
|
+
const FREE_GRAPH_LIMIT = 200;
|
|
412
457
|
const nodes = [];
|
|
413
458
|
const edges = [];
|
|
414
459
|
// ── Compute depth for each file (BFS from roots) ──
|
|
@@ -429,7 +474,7 @@ function createWebServer(getGraphFn, initialFileCache, switchProjectFn, getProje
|
|
|
429
474
|
queue.push([dep, d + 1]);
|
|
430
475
|
}
|
|
431
476
|
}
|
|
432
|
-
// Free tier: limit to first
|
|
477
|
+
// Free tier: limit to first 200 files sorted alphabetically
|
|
433
478
|
const allFiles = [...graph.files].sort();
|
|
434
479
|
const visibleFiles = isPro ? allFiles : allFiles.slice(0, FREE_GRAPH_LIMIT);
|
|
435
480
|
const visibleSet = new Set(visibleFiles);
|
|
@@ -521,14 +566,14 @@ function createWebServer(getGraphFn, initialFileCache, switchProjectFn, getProje
|
|
|
521
566
|
if (!isPro) {
|
|
522
567
|
const allFiles = [...graph.files].sort();
|
|
523
568
|
const idx = allFiles.indexOf(resolved);
|
|
524
|
-
if (idx < 0 || idx >=
|
|
525
|
-
return res.status(403).json({ error: "This file exceeds the Free tier limit (
|
|
569
|
+
if (idx < 0 || idx >= 200) {
|
|
570
|
+
return res.status(403).json({ error: "This file exceeds the Free tier limit (200 files). Upgrade to Pro for unlimited analysis.", upgrade: "https://syke.cloud/dashboard/" });
|
|
526
571
|
}
|
|
527
572
|
}
|
|
528
573
|
const impactResult = await (0, analyze_impact_1.analyzeImpact)(resolved, graph);
|
|
529
574
|
try {
|
|
530
575
|
const aiResult = await (0, analyzer_1.analyzeWithAI)(resolved, impactResult, graph);
|
|
531
|
-
const partial = !isPro && graph.files.size >
|
|
576
|
+
const partial = !isPro && graph.files.size > 200;
|
|
532
577
|
res.json({ file: impactResult.relativePath, analysis: aiResult, partial });
|
|
533
578
|
}
|
|
534
579
|
catch (err) {
|
|
@@ -792,7 +837,7 @@ function createWebServer(getGraphFn, initialFileCache, switchProjectFn, getProje
|
|
|
792
837
|
planSource: license?.source || "default",
|
|
793
838
|
expiresAt: license?.expiresAt || null,
|
|
794
839
|
licenseKey: maskedKey,
|
|
795
|
-
freeFileLimit:
|
|
840
|
+
freeFileLimit: 200,
|
|
796
841
|
sykeVersion,
|
|
797
842
|
aiProvider: aiInfo.activeProvider,
|
|
798
843
|
aiKeys: aiInfo.configured,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@syke1/mcp-server",
|
|
3
|
-
"version": "1.8.
|
|
3
|
+
"version": "1.8.2",
|
|
4
4
|
"mcpName": "io.github.khalomsky/syke",
|
|
5
5
|
"description": "AI code impact analysis MCP server — dependency graphs, cascade detection, and a mandatory build gate for AI coding agents",
|
|
6
6
|
"main": "dist/index.js",
|