@syke1/mcp-server 1.0.0 → 1.1.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.
- package/dist/index.js +14 -9
- package/dist/web/server.js +49 -11
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -68,7 +68,6 @@ function resolveFilePath(fileArg, projectRoot, sourceDir) {
|
|
|
68
68
|
let licenseStatus = { plan: "free", source: "default" };
|
|
69
69
|
// Free tier limits
|
|
70
70
|
const FREE_MAX_FILES = 50;
|
|
71
|
-
const FREE_MAX_HUB_FILES = 3;
|
|
72
71
|
/**
|
|
73
72
|
* Check if a resolved file path is within the free tier limit.
|
|
74
73
|
* Free set = first 50 files sorted alphabetically by relative path.
|
|
@@ -325,11 +324,15 @@ async function main() {
|
|
|
325
324
|
return { content: [{ type: "text", text: lines.join("\n") }] };
|
|
326
325
|
}
|
|
327
326
|
case "get_hub_files": {
|
|
327
|
+
// Pro-only feature
|
|
328
|
+
if (licenseStatus.plan !== "pro") {
|
|
329
|
+
return {
|
|
330
|
+
content: [{ type: "text", text: "get_hub_files requires SYKE Pro. Upgrade at https://syke.cloud/dashboard/\n\nSet SYKE_LICENSE_KEY in your MCP config to activate Pro features." }],
|
|
331
|
+
};
|
|
332
|
+
}
|
|
328
333
|
const requestedN = args.top_n || 10;
|
|
329
334
|
const graph = (0, graph_1.getGraph)(currentProjectRoot, currentPackageName);
|
|
330
|
-
|
|
331
|
-
const maxN = licenseStatus.plan === "pro" ? requestedN : Math.min(requestedN, FREE_MAX_HUB_FILES);
|
|
332
|
-
const hubs = (0, analyze_impact_1.getHubFiles)(graph, maxN);
|
|
335
|
+
const hubs = (0, analyze_impact_1.getHubFiles)(graph, requestedN);
|
|
333
336
|
const lines = [
|
|
334
337
|
`## Hub Files (Top ${hubs.length})`,
|
|
335
338
|
"",
|
|
@@ -341,10 +344,6 @@ async function main() {
|
|
|
341
344
|
});
|
|
342
345
|
lines.push("");
|
|
343
346
|
lines.push(`Total files in graph: ${graph.files.size}`);
|
|
344
|
-
if (licenseStatus.plan !== "pro" && requestedN > FREE_MAX_HUB_FILES) {
|
|
345
|
-
lines.push("");
|
|
346
|
-
lines.push(`Free tier shows top ${FREE_MAX_HUB_FILES} hub files. Upgrade to Pro for full ranking: https://syke.cloud/dashboard/`);
|
|
347
|
-
}
|
|
348
347
|
return { content: [{ type: "text", text: lines.join("\n") }] };
|
|
349
348
|
}
|
|
350
349
|
case "refresh_graph": {
|
|
@@ -390,6 +389,12 @@ async function main() {
|
|
|
390
389
|
};
|
|
391
390
|
}
|
|
392
391
|
case "check_warnings": {
|
|
392
|
+
// Pro-only feature (real-time monitoring)
|
|
393
|
+
if (licenseStatus.plan !== "pro") {
|
|
394
|
+
return {
|
|
395
|
+
content: [{ type: "text", text: "check_warnings requires SYKE Pro (real-time monitoring feature). Upgrade at https://syke.cloud/dashboard/\n\nSet SYKE_LICENSE_KEY in your MCP config to activate Pro features." }],
|
|
396
|
+
};
|
|
397
|
+
}
|
|
393
398
|
const shouldAck = args.acknowledge || false;
|
|
394
399
|
const warnings = (0, server_1.getUnacknowledgedWarnings)();
|
|
395
400
|
if (warnings.length === 0) {
|
|
@@ -451,7 +456,7 @@ async function main() {
|
|
|
451
456
|
console.error(`[syke] Pro activated for: ${licenseStatus.email || "unknown"}`);
|
|
452
457
|
}
|
|
453
458
|
else {
|
|
454
|
-
console.error(`[syke] Free tier: ${FREE_MAX_FILES} file limit, ai_analyze disabled`);
|
|
459
|
+
console.error(`[syke] Free tier: ${FREE_MAX_FILES} file limit, ai_analyze/get_hub_files/check_warnings disabled`);
|
|
455
460
|
console.error(`[syke] Upgrade at https://syke.cloud/dashboard/`);
|
|
456
461
|
}
|
|
457
462
|
console.error(`[syke] Project root: ${currentProjectRoot}`);
|
package/dist/web/server.js
CHANGED
|
@@ -246,6 +246,12 @@ function createWebServer(getGraphFn, fileCache, switchProjectFn, getProjectRoot,
|
|
|
246
246
|
}
|
|
247
247
|
}
|
|
248
248
|
app.get("/api/events", (_req, res) => {
|
|
249
|
+
// Pro-only: real-time monitoring via SSE
|
|
250
|
+
const license = getLicenseStatus?.();
|
|
251
|
+
if (!license || license.plan !== "pro") {
|
|
252
|
+
res.status(403).json({ error: "Real-time monitoring requires SYKE Pro.", upgrade: "https://syke.cloud/dashboard/" });
|
|
253
|
+
return;
|
|
254
|
+
}
|
|
249
255
|
res.writeHead(200, {
|
|
250
256
|
"Content-Type": "text/event-stream",
|
|
251
257
|
"Cache-Control": "no-cache",
|
|
@@ -335,6 +341,9 @@ function createWebServer(getGraphFn, fileCache, switchProjectFn, getProjectRoot,
|
|
|
335
341
|
// GET /api/graph — Cytoscape.js compatible JSON
|
|
336
342
|
app.get("/api/graph", (_req, res) => {
|
|
337
343
|
const graph = getGraphFn();
|
|
344
|
+
const license = getLicenseStatus?.();
|
|
345
|
+
const isPro = license?.plan === "pro";
|
|
346
|
+
const FREE_GRAPH_LIMIT = 50;
|
|
338
347
|
const nodes = [];
|
|
339
348
|
const edges = [];
|
|
340
349
|
// ── Compute depth for each file (BFS from roots) ──
|
|
@@ -355,7 +364,11 @@ function createWebServer(getGraphFn, fileCache, switchProjectFn, getProjectRoot,
|
|
|
355
364
|
queue.push([dep, d + 1]);
|
|
356
365
|
}
|
|
357
366
|
}
|
|
358
|
-
|
|
367
|
+
// Free tier: limit to first 50 files sorted alphabetically
|
|
368
|
+
const allFiles = [...graph.files].sort();
|
|
369
|
+
const visibleFiles = isPro ? allFiles : allFiles.slice(0, FREE_GRAPH_LIMIT);
|
|
370
|
+
const visibleSet = new Set(visibleFiles);
|
|
371
|
+
for (const file of visibleFiles) {
|
|
359
372
|
const rel = path.relative(graph.sourceDir, file).replace(/\\/g, "/");
|
|
360
373
|
const revDeps = graph.reverse.get(file) || [];
|
|
361
374
|
const dependentCount = revDeps.length;
|
|
@@ -392,13 +405,18 @@ function createWebServer(getGraphFn, fileCache, switchProjectFn, getProjectRoot,
|
|
|
392
405
|
});
|
|
393
406
|
}
|
|
394
407
|
for (const [file, deps] of graph.forward) {
|
|
408
|
+
// Only include edges where both source and target are in the visible set
|
|
409
|
+
if (!visibleSet.has(file))
|
|
410
|
+
continue;
|
|
395
411
|
const from = path.relative(graph.sourceDir, file).replace(/\\/g, "/");
|
|
396
412
|
for (const d of deps) {
|
|
413
|
+
if (!visibleSet.has(d))
|
|
414
|
+
continue;
|
|
397
415
|
const to = path.relative(graph.sourceDir, d).replace(/\\/g, "/");
|
|
398
416
|
edges.push({ data: { source: from, target: to } });
|
|
399
417
|
}
|
|
400
418
|
}
|
|
401
|
-
res.json({ nodes, edges });
|
|
419
|
+
res.json({ nodes, edges, totalFiles: graph.files.size, limited: !isPro && graph.files.size > FREE_GRAPH_LIMIT });
|
|
402
420
|
});
|
|
403
421
|
// GET /api/impact/:file — Impact analysis for a specific file
|
|
404
422
|
app.get("/api/impact/*splat", (req, res) => {
|
|
@@ -443,15 +461,16 @@ function createWebServer(getGraphFn, fileCache, switchProjectFn, getProjectRoot,
|
|
|
443
461
|
res.status(500).json({ error: err.message || "AI analysis failed" });
|
|
444
462
|
}
|
|
445
463
|
});
|
|
446
|
-
// GET /api/hub-files — Top hub files ranking (
|
|
464
|
+
// GET /api/hub-files — Top hub files ranking (Pro only)
|
|
447
465
|
app.get("/api/hub-files", (req, res) => {
|
|
448
|
-
const requested = parseInt(req.query.top) || 10;
|
|
449
466
|
const license = getLicenseStatus?.();
|
|
450
|
-
|
|
451
|
-
|
|
467
|
+
if (!license || license.plan !== "pro") {
|
|
468
|
+
return res.status(403).json({ error: "Hub files ranking requires SYKE Pro.", upgrade: "https://syke.cloud/dashboard/" });
|
|
469
|
+
}
|
|
470
|
+
const requested = parseInt(req.query.top) || 10;
|
|
452
471
|
const graph = getGraphFn();
|
|
453
|
-
const hubs = (0, analyze_impact_1.getHubFiles)(graph,
|
|
454
|
-
res.json({ hubs, totalFiles: graph.files.size, limited:
|
|
472
|
+
const hubs = (0, analyze_impact_1.getHubFiles)(graph, requested);
|
|
473
|
+
res.json({ hubs, totalFiles: graph.files.size, limited: false, plan: "pro" });
|
|
455
474
|
});
|
|
456
475
|
// POST /api/connected-code — Batch load code from file + connected nodes
|
|
457
476
|
app.post("/api/connected-code", (req, res) => {
|
|
@@ -517,8 +536,12 @@ function createWebServer(getGraphFn, fileCache, switchProjectFn, getProjectRoot,
|
|
|
517
536
|
res.status(500).json({ error: err.message });
|
|
518
537
|
}
|
|
519
538
|
});
|
|
520
|
-
// GET /api/cycles — Detect circular dependencies
|
|
539
|
+
// GET /api/cycles — Detect circular dependencies (Pro only)
|
|
521
540
|
app.get("/api/cycles", (_req, res) => {
|
|
541
|
+
const license = getLicenseStatus?.();
|
|
542
|
+
if (!license || license.plan !== "pro") {
|
|
543
|
+
return res.status(403).json({ error: "This feature requires SYKE Pro.", upgrade: "https://syke.cloud/dashboard/" });
|
|
544
|
+
}
|
|
522
545
|
const graph = getGraphFn();
|
|
523
546
|
const toRel = (f) => path.relative(graph.sourceDir, f).replace(/\\/g, "/");
|
|
524
547
|
const cycles = [];
|
|
@@ -601,8 +624,12 @@ function createWebServer(getGraphFn, fileCache, switchProjectFn, getProjectRoot,
|
|
|
601
624
|
}
|
|
602
625
|
res.json({ path: pathResult, distance: pathResult.length - 1 });
|
|
603
626
|
});
|
|
604
|
-
// GET /api/simulate-delete/:file — Simulate file removal
|
|
627
|
+
// GET /api/simulate-delete/:file — Simulate file removal (Pro only)
|
|
605
628
|
app.get("/api/simulate-delete/*splat", (req, res) => {
|
|
629
|
+
const license = getLicenseStatus?.();
|
|
630
|
+
if (!license || license.plan !== "pro") {
|
|
631
|
+
return res.status(403).json({ error: "This feature requires SYKE Pro.", upgrade: "https://syke.cloud/dashboard/" });
|
|
632
|
+
}
|
|
606
633
|
const splat = req.params.splat;
|
|
607
634
|
const fileParam = Array.isArray(splat) ? splat.join("/") : splat;
|
|
608
635
|
if (!fileParam)
|
|
@@ -718,13 +745,24 @@ function createWebServer(getGraphFn, fileCache, switchProjectFn, getProjectRoot,
|
|
|
718
745
|
res.status(500).json({ error: err.message });
|
|
719
746
|
}
|
|
720
747
|
});
|
|
721
|
-
// POST /api/switch-project — Switch to a different project folder
|
|
748
|
+
// POST /api/switch-project — Switch to a different project folder (Pro only)
|
|
722
749
|
app.post("/api/switch-project", (req, res) => {
|
|
723
750
|
const { projectRoot } = req.body;
|
|
724
751
|
if (!projectRoot || typeof projectRoot !== "string") {
|
|
725
752
|
return res.status(400).json({ error: "projectRoot is required" });
|
|
726
753
|
}
|
|
727
754
|
const normalized = path.normalize(projectRoot);
|
|
755
|
+
// Free tier: only 1 project allowed — block switch to a different project
|
|
756
|
+
const license = getLicenseStatus?.();
|
|
757
|
+
if (!license || license.plan !== "pro") {
|
|
758
|
+
const currentRoot = getProjectRoot ? path.normalize(getProjectRoot()) : null;
|
|
759
|
+
if (currentRoot && normalized !== currentRoot) {
|
|
760
|
+
return res.status(403).json({
|
|
761
|
+
error: "Multiple projects require SYKE Pro. Free tier supports 1 project.",
|
|
762
|
+
upgrade: "https://syke.cloud/dashboard/",
|
|
763
|
+
});
|
|
764
|
+
}
|
|
765
|
+
}
|
|
728
766
|
if (!fs.existsSync(normalized) || !fs.statSync(normalized).isDirectory()) {
|
|
729
767
|
return res.status(400).json({ error: `Directory not found: ${normalized}` });
|
|
730
768
|
}
|
package/package.json
CHANGED