@syke1/mcp-server 1.3.1 ā 1.3.3
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 +33 -16
- package/dist/license/validator.js +4 -0
- package/dist/web/public/app.js +27 -0
- package/dist/web/public/index.html +28 -0
- package/dist/web/public/style.css +147 -0
- package/dist/web/server.d.ts +3 -0
- package/dist/web/server.js +20 -8
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -86,6 +86,15 @@ function isFileInFreeSet(resolvedPath, graph) {
|
|
|
86
86
|
return idx >= 0 && idx < FREE_MAX_FILES;
|
|
87
87
|
}
|
|
88
88
|
const PRO_UPGRADE_MSG = "This file exceeds the Free tier limit (50 files). Upgrade to Pro for unlimited analysis: https://syke.cloud/dashboard/";
|
|
89
|
+
function getProToolError(toolName) {
|
|
90
|
+
if (licenseStatus.error) {
|
|
91
|
+
return `${toolName}: ${licenseStatus.error}`;
|
|
92
|
+
}
|
|
93
|
+
if (licenseStatus.expiresAt) {
|
|
94
|
+
return `${toolName}: Trial expired. Upgrade at https://syke.cloud/dashboard/`;
|
|
95
|
+
}
|
|
96
|
+
return `${toolName} requires SYKE Pro. Set SYKE_LICENSE_KEY in your MCP config or sign up at https://syke.cloud`;
|
|
97
|
+
}
|
|
89
98
|
async function main() {
|
|
90
99
|
// Check license before starting (graceful fallback for hosted environments like Smithery)
|
|
91
100
|
try {
|
|
@@ -111,7 +120,7 @@ async function main() {
|
|
|
111
120
|
};
|
|
112
121
|
process.on("SIGINT", shutdown);
|
|
113
122
|
process.on("SIGTERM", shutdown);
|
|
114
|
-
const server = new index_js_1.Server({ name: "syke", version: "1.3.
|
|
123
|
+
const server = new index_js_1.Server({ name: "syke", version: "1.3.3" }, { capabilities: { tools: {} } });
|
|
115
124
|
// List tools
|
|
116
125
|
server.setRequestHandler(types_js_1.ListToolsRequestSchema, async () => ({
|
|
117
126
|
tools: [
|
|
@@ -218,6 +227,16 @@ async function main() {
|
|
|
218
227
|
},
|
|
219
228
|
],
|
|
220
229
|
}));
|
|
230
|
+
// Dashboard URL footer ā shown only on the first successful tool call
|
|
231
|
+
let firstToolCall = true;
|
|
232
|
+
const DASHBOARD_FOOTER = `\n\n---\nš SYKE Dashboard: http://localhost:${WEB_PORT}`;
|
|
233
|
+
function appendDashboardFooter(text) {
|
|
234
|
+
if (firstToolCall && currentProjectRoot) {
|
|
235
|
+
firstToolCall = false;
|
|
236
|
+
return text + DASHBOARD_FOOTER;
|
|
237
|
+
}
|
|
238
|
+
return text;
|
|
239
|
+
}
|
|
221
240
|
// Handle tool calls
|
|
222
241
|
server.setRequestHandler(types_js_1.CallToolRequestSchema, async (request) => {
|
|
223
242
|
const { name, arguments: args } = request.params;
|
|
@@ -228,7 +247,7 @@ async function main() {
|
|
|
228
247
|
const result = (0, gate_build_1.gateCheck)(graph, files);
|
|
229
248
|
return {
|
|
230
249
|
content: [
|
|
231
|
-
{ type: "text", text: (0, gate_build_1.formatGateResult)(result) },
|
|
250
|
+
{ type: "text", text: appendDashboardFooter((0, gate_build_1.formatGateResult)(result)) },
|
|
232
251
|
],
|
|
233
252
|
isError: result.verdict === "FAIL",
|
|
234
253
|
};
|
|
@@ -270,7 +289,7 @@ async function main() {
|
|
|
270
289
|
lines.push(`- ${d}`);
|
|
271
290
|
}
|
|
272
291
|
}
|
|
273
|
-
return { content: [{ type: "text", text: lines.join("\n") }] };
|
|
292
|
+
return { content: [{ type: "text", text: appendDashboardFooter(lines.join("\n")) }] };
|
|
274
293
|
}
|
|
275
294
|
case "check_safe": {
|
|
276
295
|
const file = args.file;
|
|
@@ -295,7 +314,7 @@ async function main() {
|
|
|
295
314
|
content: [
|
|
296
315
|
{
|
|
297
316
|
type: "text",
|
|
298
|
-
text: `${result.riskLevel} ā ${rel} impacts ${result.totalImpacted} file(s)
|
|
317
|
+
text: appendDashboardFooter(`${result.riskLevel} ā ${rel} impacts ${result.totalImpacted} file(s)`),
|
|
299
318
|
},
|
|
300
319
|
],
|
|
301
320
|
};
|
|
@@ -339,7 +358,7 @@ async function main() {
|
|
|
339
358
|
// Pro-only feature
|
|
340
359
|
if (licenseStatus.plan !== "pro") {
|
|
341
360
|
return {
|
|
342
|
-
content: [{ type: "text", text: "get_hub_files
|
|
361
|
+
content: [{ type: "text", text: getProToolError("get_hub_files") }],
|
|
343
362
|
};
|
|
344
363
|
}
|
|
345
364
|
const requestedN = args.top_n || 10;
|
|
@@ -373,12 +392,7 @@ async function main() {
|
|
|
373
392
|
// Pro-only feature
|
|
374
393
|
if (licenseStatus.plan !== "pro") {
|
|
375
394
|
return {
|
|
376
|
-
content: [
|
|
377
|
-
{
|
|
378
|
-
type: "text",
|
|
379
|
-
text: "ai_analyze requires SYKE Pro. Upgrade at https://syke.cloud/dashboard/\n\nSet SYKE_LICENSE_KEY in your MCP config to activate Pro features.",
|
|
380
|
-
},
|
|
381
|
-
],
|
|
395
|
+
content: [{ type: "text", text: getProToolError("ai_analyze") }],
|
|
382
396
|
};
|
|
383
397
|
}
|
|
384
398
|
const file = args.file;
|
|
@@ -397,14 +411,14 @@ async function main() {
|
|
|
397
411
|
const impactResult = (0, analyze_impact_1.analyzeImpact)(resolved, graph);
|
|
398
412
|
const aiResult = await (0, analyzer_1.analyzeWithAI)(resolved, impactResult, graph);
|
|
399
413
|
return {
|
|
400
|
-
content: [{ type: "text", text: aiResult }],
|
|
414
|
+
content: [{ type: "text", text: appendDashboardFooter(aiResult) }],
|
|
401
415
|
};
|
|
402
416
|
}
|
|
403
417
|
case "check_warnings": {
|
|
404
418
|
// Pro-only feature (real-time monitoring)
|
|
405
419
|
if (licenseStatus.plan !== "pro") {
|
|
406
420
|
return {
|
|
407
|
-
content: [{ type: "text", text: "check_warnings
|
|
421
|
+
content: [{ type: "text", text: getProToolError("check_warnings") }],
|
|
408
422
|
};
|
|
409
423
|
}
|
|
410
424
|
const shouldAck = args.acknowledge || false;
|
|
@@ -448,7 +462,7 @@ async function main() {
|
|
|
448
462
|
lines.push(`${count} warning(s) acknowledged.`);
|
|
449
463
|
}
|
|
450
464
|
return {
|
|
451
|
-
content: [{ type: "text", text: lines.join("\n") }],
|
|
465
|
+
content: [{ type: "text", text: appendDashboardFooter(lines.join("\n")) }],
|
|
452
466
|
};
|
|
453
467
|
}
|
|
454
468
|
default:
|
|
@@ -461,8 +475,11 @@ async function main() {
|
|
|
461
475
|
}
|
|
462
476
|
});
|
|
463
477
|
// Pre-warm the graph (skip if no project root ā e.g. Smithery scan)
|
|
464
|
-
console.error(`[syke] Starting SYKE MCP Server v1.3.
|
|
478
|
+
console.error(`[syke] Starting SYKE MCP Server v1.3.3`);
|
|
465
479
|
console.error(`[syke] License: ${licenseStatus.plan.toUpperCase()} (${licenseStatus.source})`);
|
|
480
|
+
if (licenseStatus.expiresAt) {
|
|
481
|
+
console.error(`[syke] Expires: ${licenseStatus.expiresAt}`);
|
|
482
|
+
}
|
|
466
483
|
// Log AI provider status
|
|
467
484
|
const aiProvider = (0, provider_1.getAIProvider)();
|
|
468
485
|
if (aiProvider) {
|
|
@@ -553,7 +570,7 @@ main().catch((err) => {
|
|
|
553
570
|
* See: https://smithery.ai/docs/deploy#sandbox-server
|
|
554
571
|
*/
|
|
555
572
|
function createSandboxServer() {
|
|
556
|
-
const sandboxServer = new index_js_1.Server({ name: "syke", version: "1.3.
|
|
573
|
+
const sandboxServer = new index_js_1.Server({ name: "syke", version: "1.3.3" }, { capabilities: { tools: {} } });
|
|
557
574
|
sandboxServer.setRequestHandler(types_js_1.ListToolsRequestSchema, async () => ({
|
|
558
575
|
tools: [
|
|
559
576
|
{
|
|
@@ -255,6 +255,10 @@ async function checkLicense() {
|
|
|
255
255
|
}
|
|
256
256
|
// Try online validation (with device binding)
|
|
257
257
|
const result = await validateOnline(key);
|
|
258
|
+
if (!result.valid) {
|
|
259
|
+
const reason = result.error || "invalid key or expired";
|
|
260
|
+
console.error(`[syke] License validation failed: ${reason}`);
|
|
261
|
+
}
|
|
258
262
|
if (result.valid) {
|
|
259
263
|
// Update cache
|
|
260
264
|
writeCache({
|
package/dist/web/public/app.js
CHANGED
|
@@ -51,6 +51,27 @@ document.addEventListener("DOMContentLoaded", async () => {
|
|
|
51
51
|
initSSE();
|
|
52
52
|
});
|
|
53
53
|
|
|
54
|
+
// āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
|
|
55
|
+
// WELCOME OVERLAY
|
|
56
|
+
// āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
|
|
57
|
+
function showWelcomeOverlay() {
|
|
58
|
+
const overlay = document.getElementById("welcome-overlay");
|
|
59
|
+
if (overlay) overlay.classList.remove("hidden");
|
|
60
|
+
|
|
61
|
+
const btn = document.getElementById("btn-welcome-open");
|
|
62
|
+
if (btn && !btn._bound) {
|
|
63
|
+
btn.addEventListener("click", () => {
|
|
64
|
+
document.getElementById("btn-change-project").click();
|
|
65
|
+
});
|
|
66
|
+
btn._bound = true;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function hideWelcomeOverlay() {
|
|
71
|
+
const overlay = document.getElementById("welcome-overlay");
|
|
72
|
+
if (overlay) overlay.classList.add("hidden");
|
|
73
|
+
}
|
|
74
|
+
|
|
54
75
|
// āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
|
|
55
76
|
// GRAPH LOADING
|
|
56
77
|
// āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
|
|
@@ -59,6 +80,12 @@ async function loadGraph() {
|
|
|
59
80
|
const raw = await res.json();
|
|
60
81
|
console.log("[SYKE]", raw.nodes.length, "nodes", raw.edges.length, "edges");
|
|
61
82
|
|
|
83
|
+
if (raw.nodes.length === 0) {
|
|
84
|
+
showWelcomeOverlay();
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
hideWelcomeOverlay();
|
|
88
|
+
|
|
62
89
|
const nodes = raw.nodes.map(n => {
|
|
63
90
|
const layer = n.data.layer || "UTIL";
|
|
64
91
|
const c = LAYER_CENTERS[layer] || LAYER_CENTERS.UTIL;
|
|
@@ -56,6 +56,34 @@
|
|
|
56
56
|
<input type="text" id="search-input" placeholder="SEARCH TARGET...">
|
|
57
57
|
</div>
|
|
58
58
|
<div id="3d-graph"></div>
|
|
59
|
+
<!-- Welcome Overlay (shown when no project loaded) -->
|
|
60
|
+
<div id="welcome-overlay" class="welcome-overlay hidden">
|
|
61
|
+
<div class="welcome-content">
|
|
62
|
+
<div class="welcome-logo">
|
|
63
|
+
<div class="welcome-pulse-ring"><span class="welcome-pulse-dot"></span></div>
|
|
64
|
+
<span class="welcome-title">SYKE</span>
|
|
65
|
+
</div>
|
|
66
|
+
<p class="welcome-subtitle">CODE IMPACT RADAR</p>
|
|
67
|
+
<p class="welcome-msg">Open a project to get started</p>
|
|
68
|
+
<button id="btn-welcome-open" class="welcome-open-btn">OPEN PROJECT</button>
|
|
69
|
+
<div class="welcome-steps">
|
|
70
|
+
<div class="welcome-step">
|
|
71
|
+
<span class="step-num">1</span>
|
|
72
|
+
<span class="step-text">Open Project</span>
|
|
73
|
+
</div>
|
|
74
|
+
<div class="welcome-step-arrow">→</div>
|
|
75
|
+
<div class="welcome-step">
|
|
76
|
+
<span class="step-num">2</span>
|
|
77
|
+
<span class="step-text">Explore Graph</span>
|
|
78
|
+
</div>
|
|
79
|
+
<div class="welcome-step-arrow">→</div>
|
|
80
|
+
<div class="welcome-step">
|
|
81
|
+
<span class="step-num">3</span>
|
|
82
|
+
<span class="step-text">Monitor Changes</span>
|
|
83
|
+
</div>
|
|
84
|
+
</div>
|
|
85
|
+
</div>
|
|
86
|
+
</div>
|
|
59
87
|
<!-- HTML overlay for node labels -->
|
|
60
88
|
<div id="node-labels"></div>
|
|
61
89
|
<!-- Layer Legend (clickable filter) -->
|
|
@@ -1825,3 +1825,150 @@ main {
|
|
|
1825
1825
|
font-size: 11px;
|
|
1826
1826
|
letter-spacing: 2px;
|
|
1827
1827
|
}
|
|
1828
|
+
|
|
1829
|
+
/* āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā */
|
|
1830
|
+
/* Welcome Overlay */
|
|
1831
|
+
/* āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā */
|
|
1832
|
+
.welcome-overlay {
|
|
1833
|
+
position: absolute;
|
|
1834
|
+
top: 0; left: 0; right: 0; bottom: 0;
|
|
1835
|
+
display: flex;
|
|
1836
|
+
align-items: center;
|
|
1837
|
+
justify-content: center;
|
|
1838
|
+
z-index: 50;
|
|
1839
|
+
background: radial-gradient(ellipse at center, rgba(13,26,48,0.95) 0%, rgba(5,10,24,0.98) 70%);
|
|
1840
|
+
backdrop-filter: blur(2px);
|
|
1841
|
+
}
|
|
1842
|
+
|
|
1843
|
+
.welcome-overlay.hidden { display: none; }
|
|
1844
|
+
|
|
1845
|
+
.welcome-content {
|
|
1846
|
+
display: flex;
|
|
1847
|
+
flex-direction: column;
|
|
1848
|
+
align-items: center;
|
|
1849
|
+
gap: 16px;
|
|
1850
|
+
animation: welcome-fade-in 0.8s ease-out;
|
|
1851
|
+
}
|
|
1852
|
+
|
|
1853
|
+
@keyframes welcome-fade-in {
|
|
1854
|
+
0% { opacity: 0; transform: translateY(20px); }
|
|
1855
|
+
100% { opacity: 1; transform: translateY(0); }
|
|
1856
|
+
}
|
|
1857
|
+
|
|
1858
|
+
.welcome-logo {
|
|
1859
|
+
display: flex;
|
|
1860
|
+
align-items: center;
|
|
1861
|
+
gap: 16px;
|
|
1862
|
+
}
|
|
1863
|
+
|
|
1864
|
+
.welcome-pulse-ring {
|
|
1865
|
+
position: relative;
|
|
1866
|
+
width: 28px;
|
|
1867
|
+
height: 28px;
|
|
1868
|
+
display: flex;
|
|
1869
|
+
align-items: center;
|
|
1870
|
+
justify-content: center;
|
|
1871
|
+
}
|
|
1872
|
+
|
|
1873
|
+
.welcome-pulse-ring::before {
|
|
1874
|
+
content: '';
|
|
1875
|
+
position: absolute;
|
|
1876
|
+
width: 28px; height: 28px;
|
|
1877
|
+
border-radius: 50%;
|
|
1878
|
+
border: 1px solid var(--risk-high);
|
|
1879
|
+
animation: pulse-ring 2s ease-out infinite;
|
|
1880
|
+
}
|
|
1881
|
+
|
|
1882
|
+
.welcome-pulse-dot {
|
|
1883
|
+
width: 10px;
|
|
1884
|
+
height: 10px;
|
|
1885
|
+
border-radius: 50%;
|
|
1886
|
+
background: var(--risk-high);
|
|
1887
|
+
box-shadow: 0 0 12px var(--risk-high);
|
|
1888
|
+
animation: pulse-glow 2s ease-in-out infinite;
|
|
1889
|
+
}
|
|
1890
|
+
|
|
1891
|
+
.welcome-title {
|
|
1892
|
+
font-size: 42px;
|
|
1893
|
+
font-weight: 700;
|
|
1894
|
+
letter-spacing: 12px;
|
|
1895
|
+
color: var(--accent);
|
|
1896
|
+
text-shadow: var(--glow-cyan), 0 0 40px rgba(0,212,255,0.2);
|
|
1897
|
+
}
|
|
1898
|
+
|
|
1899
|
+
.welcome-subtitle {
|
|
1900
|
+
font-size: 11px;
|
|
1901
|
+
color: var(--text-secondary);
|
|
1902
|
+
letter-spacing: 6px;
|
|
1903
|
+
margin-top: -8px;
|
|
1904
|
+
}
|
|
1905
|
+
|
|
1906
|
+
.welcome-msg {
|
|
1907
|
+
font-size: 14px;
|
|
1908
|
+
color: var(--text-primary);
|
|
1909
|
+
letter-spacing: 1px;
|
|
1910
|
+
margin-top: 8px;
|
|
1911
|
+
}
|
|
1912
|
+
|
|
1913
|
+
.welcome-open-btn {
|
|
1914
|
+
padding: 12px 40px;
|
|
1915
|
+
background: rgba(0,212,255,0.1);
|
|
1916
|
+
color: var(--accent);
|
|
1917
|
+
border: 1px solid var(--accent);
|
|
1918
|
+
border-radius: 3px;
|
|
1919
|
+
cursor: pointer;
|
|
1920
|
+
font-size: 13px;
|
|
1921
|
+
font-family: inherit;
|
|
1922
|
+
font-weight: 700;
|
|
1923
|
+
letter-spacing: 4px;
|
|
1924
|
+
transition: all 0.3s;
|
|
1925
|
+
margin-top: 8px;
|
|
1926
|
+
}
|
|
1927
|
+
|
|
1928
|
+
.welcome-open-btn:hover {
|
|
1929
|
+
background: rgba(0,212,255,0.2);
|
|
1930
|
+
box-shadow: var(--glow-cyan), 0 0 40px rgba(0,212,255,0.15);
|
|
1931
|
+
transform: translateY(-1px);
|
|
1932
|
+
}
|
|
1933
|
+
|
|
1934
|
+
.welcome-steps {
|
|
1935
|
+
display: flex;
|
|
1936
|
+
align-items: center;
|
|
1937
|
+
gap: 12px;
|
|
1938
|
+
margin-top: 24px;
|
|
1939
|
+
padding: 16px 24px;
|
|
1940
|
+
background: rgba(0,0,0,0.3);
|
|
1941
|
+
border: 1px solid var(--border);
|
|
1942
|
+
border-radius: 4px;
|
|
1943
|
+
}
|
|
1944
|
+
|
|
1945
|
+
.welcome-step {
|
|
1946
|
+
display: flex;
|
|
1947
|
+
align-items: center;
|
|
1948
|
+
gap: 8px;
|
|
1949
|
+
}
|
|
1950
|
+
|
|
1951
|
+
.step-num {
|
|
1952
|
+
width: 22px;
|
|
1953
|
+
height: 22px;
|
|
1954
|
+
border-radius: 50%;
|
|
1955
|
+
border: 1px solid var(--accent-dim);
|
|
1956
|
+
display: flex;
|
|
1957
|
+
align-items: center;
|
|
1958
|
+
justify-content: center;
|
|
1959
|
+
font-size: 10px;
|
|
1960
|
+
font-weight: 700;
|
|
1961
|
+
color: var(--accent);
|
|
1962
|
+
}
|
|
1963
|
+
|
|
1964
|
+
.step-text {
|
|
1965
|
+
font-size: 11px;
|
|
1966
|
+
color: var(--text-secondary);
|
|
1967
|
+
letter-spacing: 1px;
|
|
1968
|
+
}
|
|
1969
|
+
|
|
1970
|
+
.welcome-step-arrow {
|
|
1971
|
+
color: var(--text-secondary);
|
|
1972
|
+
font-size: 14px;
|
|
1973
|
+
opacity: 0.5;
|
|
1974
|
+
}
|
package/dist/web/server.d.ts
CHANGED
|
@@ -26,4 +26,7 @@ export interface SwitchProjectResult {
|
|
|
26
26
|
}
|
|
27
27
|
export declare function createWebServer(getGraphFn: () => DependencyGraph, fileCache?: FileCache, switchProjectFn?: (newRoot: string) => SwitchProjectResult, getProjectRoot?: () => string, getPackageName?: () => string, getLicenseStatus?: () => {
|
|
28
28
|
plan: string;
|
|
29
|
+
expiresAt?: string;
|
|
30
|
+
error?: string;
|
|
31
|
+
source?: string;
|
|
29
32
|
}): import("express-serve-static-core").Express;
|
package/dist/web/server.js
CHANGED
|
@@ -245,11 +245,26 @@ function createWebServer(getGraphFn, fileCache, switchProjectFn, getProjectRoot,
|
|
|
245
245
|
}
|
|
246
246
|
}
|
|
247
247
|
}
|
|
248
|
+
/**
|
|
249
|
+
* Build a specific error message for Pro-only features based on license state.
|
|
250
|
+
*/
|
|
251
|
+
function getProFeatureError(featureName) {
|
|
252
|
+
const license = getLicenseStatus?.();
|
|
253
|
+
const upgrade = "https://syke.cloud/dashboard/";
|
|
254
|
+
if (license?.error) {
|
|
255
|
+
return { error: `${featureName}: ${license.error}`, requiresPro: true, upgrade };
|
|
256
|
+
}
|
|
257
|
+
if (license?.source === "online" && license?.expiresAt) {
|
|
258
|
+
// Had a license but it's no longer valid (expired trial or subscription)
|
|
259
|
+
return { error: `Trial expired. Upgrade at ${upgrade}`, requiresPro: true, upgrade };
|
|
260
|
+
}
|
|
261
|
+
return { error: `${featureName} requires SYKE Pro. Set SYKE_LICENSE_KEY or sign up at https://syke.cloud`, requiresPro: true, upgrade };
|
|
262
|
+
}
|
|
248
263
|
app.get("/api/events", (_req, res) => {
|
|
249
264
|
// Pro-only: real-time monitoring via SSE
|
|
250
265
|
const license = getLicenseStatus?.();
|
|
251
266
|
if (!license || license.plan !== "pro") {
|
|
252
|
-
res.status(403).json(
|
|
267
|
+
res.status(403).json(getProFeatureError("Real-time monitoring"));
|
|
253
268
|
return;
|
|
254
269
|
}
|
|
255
270
|
res.writeHead(200, {
|
|
@@ -438,10 +453,7 @@ function createWebServer(getGraphFn, fileCache, switchProjectFn, getProjectRoot,
|
|
|
438
453
|
// License check ā Pro only
|
|
439
454
|
const license = getLicenseStatus?.();
|
|
440
455
|
if (!license || license.plan !== "pro") {
|
|
441
|
-
return res.status(403).json(
|
|
442
|
-
error: "AI analysis requires SYKE Pro. Upgrade at https://syke.cloud/dashboard/",
|
|
443
|
-
requiresPro: true,
|
|
444
|
-
});
|
|
456
|
+
return res.status(403).json(getProFeatureError("AI analysis"));
|
|
445
457
|
}
|
|
446
458
|
const { file } = req.body;
|
|
447
459
|
if (!file) {
|
|
@@ -465,7 +477,7 @@ function createWebServer(getGraphFn, fileCache, switchProjectFn, getProjectRoot,
|
|
|
465
477
|
app.get("/api/hub-files", (req, res) => {
|
|
466
478
|
const license = getLicenseStatus?.();
|
|
467
479
|
if (!license || license.plan !== "pro") {
|
|
468
|
-
return res.status(403).json(
|
|
480
|
+
return res.status(403).json(getProFeatureError("Hub files ranking"));
|
|
469
481
|
}
|
|
470
482
|
const requested = parseInt(req.query.top) || 10;
|
|
471
483
|
const graph = getGraphFn();
|
|
@@ -540,7 +552,7 @@ function createWebServer(getGraphFn, fileCache, switchProjectFn, getProjectRoot,
|
|
|
540
552
|
app.get("/api/cycles", (_req, res) => {
|
|
541
553
|
const license = getLicenseStatus?.();
|
|
542
554
|
if (!license || license.plan !== "pro") {
|
|
543
|
-
return res.status(403).json(
|
|
555
|
+
return res.status(403).json(getProFeatureError("Cycle detection"));
|
|
544
556
|
}
|
|
545
557
|
const graph = getGraphFn();
|
|
546
558
|
const toRel = (f) => path.relative(graph.sourceDir, f).replace(/\\/g, "/");
|
|
@@ -628,7 +640,7 @@ function createWebServer(getGraphFn, fileCache, switchProjectFn, getProjectRoot,
|
|
|
628
640
|
app.get("/api/simulate-delete/*splat", (req, res) => {
|
|
629
641
|
const license = getLicenseStatus?.();
|
|
630
642
|
if (!license || license.plan !== "pro") {
|
|
631
|
-
return res.status(403).json(
|
|
643
|
+
return res.status(403).json(getProFeatureError("Delete simulation"));
|
|
632
644
|
}
|
|
633
645
|
const splat = req.params.splat;
|
|
634
646
|
const fileParam = Array.isArray(splat) ? splat.join("/") : splat;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@syke1/mcp-server",
|
|
3
|
-
"version": "1.3.
|
|
3
|
+
"version": "1.3.3",
|
|
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",
|