@syke1/mcp-server 1.4.10 → 1.4.12
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 +13 -0
- package/dist/web/public/app.js +89 -0
- package/dist/web/public/index.html +7 -0
- package/dist/web/public/style.css +48 -0
- package/dist/web/server.d.ts +5 -0
- package/dist/web/server.js +22 -2
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -607,6 +607,7 @@ async function main() {
|
|
|
607
607
|
},
|
|
608
608
|
// getAIInfoFn
|
|
609
609
|
() => {
|
|
610
|
+
const forced = (0, config_1.getConfig)("aiProvider", "SYKE_AI_PROVIDER") || null;
|
|
610
611
|
return {
|
|
611
612
|
activeProvider: (0, provider_1.getProviderName)(),
|
|
612
613
|
configured: {
|
|
@@ -614,6 +615,18 @@ async function main() {
|
|
|
614
615
|
openai: !!(0, config_1.getConfig)("openaiKey", "OPENAI_KEY"),
|
|
615
616
|
anthropic: !!(0, config_1.getConfig)("anthropicKey", "ANTHROPIC_KEY"),
|
|
616
617
|
},
|
|
618
|
+
forced,
|
|
619
|
+
};
|
|
620
|
+
},
|
|
621
|
+
// setAIProviderFn
|
|
622
|
+
(provider) => {
|
|
623
|
+
(0, config_1.setConfig)("aiProvider", provider === "auto" ? null : provider);
|
|
624
|
+
(0, provider_1.resetAIProvider)();
|
|
625
|
+
const forced = (0, config_1.getConfig)("aiProvider", "SYKE_AI_PROVIDER") || null;
|
|
626
|
+
return {
|
|
627
|
+
success: true,
|
|
628
|
+
activeProvider: (0, provider_1.getProviderName)(),
|
|
629
|
+
forced,
|
|
617
630
|
};
|
|
618
631
|
});
|
|
619
632
|
webServerHandle = { setFileCache: setWebFileCache };
|
package/dist/web/public/app.js
CHANGED
|
@@ -465,6 +465,7 @@ document.addEventListener("DOMContentLoaded", async () => {
|
|
|
465
465
|
setupProjectModal();
|
|
466
466
|
setupLicenseModal();
|
|
467
467
|
setupAIKeysModal();
|
|
468
|
+
setupAIProviderSelector();
|
|
468
469
|
setupFileTree();
|
|
469
470
|
initSSE();
|
|
470
471
|
startHealthCheck();
|
|
@@ -4079,6 +4080,8 @@ function setupAIKeysModal() {
|
|
|
4079
4080
|
var placeholders = { gemini: "AIzaSy...", openai: "sk-...", anthropic: "sk-ant-..." };
|
|
4080
4081
|
input.placeholder = placeholders[provider] || "";
|
|
4081
4082
|
}
|
|
4083
|
+
// Refresh provider selector to update enabled/disabled options
|
|
4084
|
+
if (window._refreshAIProviderSelector) window._refreshAIProviderSelector();
|
|
4082
4085
|
}
|
|
4083
4086
|
} catch (err) {
|
|
4084
4087
|
var statusEl = row.querySelector(".ai-key-status");
|
|
@@ -4101,3 +4104,89 @@ function setupAIKeysModal() {
|
|
|
4101
4104
|
}
|
|
4102
4105
|
});
|
|
4103
4106
|
}
|
|
4107
|
+
|
|
4108
|
+
// ══════════════════════════════════════════════════════════════
|
|
4109
|
+
// AI PROVIDER SELECTOR
|
|
4110
|
+
// ══════════════════════════════════════════════════════════════
|
|
4111
|
+
function setupAIProviderSelector() {
|
|
4112
|
+
const select = document.getElementById("ai-provider-select");
|
|
4113
|
+
const applyBtn = document.getElementById("btn-ai-apply");
|
|
4114
|
+
if (!select || !applyBtn) return;
|
|
4115
|
+
|
|
4116
|
+
// Refresh selector state from project-info
|
|
4117
|
+
async function refreshSelector() {
|
|
4118
|
+
try {
|
|
4119
|
+
const res = await fetch("/api/project-info");
|
|
4120
|
+
const info = await res.json();
|
|
4121
|
+
updateSelectorState(info.aiKeys || {}, info.aiProviderForced || null);
|
|
4122
|
+
} catch {}
|
|
4123
|
+
}
|
|
4124
|
+
|
|
4125
|
+
function updateSelectorState(aiKeys, forced) {
|
|
4126
|
+
// Enable/disable options based on configured keys
|
|
4127
|
+
var options = select.querySelectorAll("option");
|
|
4128
|
+
options.forEach(function(opt) {
|
|
4129
|
+
if (opt.value === "auto") {
|
|
4130
|
+
opt.disabled = false;
|
|
4131
|
+
return;
|
|
4132
|
+
}
|
|
4133
|
+
var hasKey = aiKeys[opt.value] || false;
|
|
4134
|
+
opt.disabled = !hasKey;
|
|
4135
|
+
});
|
|
4136
|
+
|
|
4137
|
+
// Set selected value
|
|
4138
|
+
if (forced && ["gemini", "openai", "anthropic"].includes(forced)) {
|
|
4139
|
+
select.value = forced;
|
|
4140
|
+
} else {
|
|
4141
|
+
select.value = "auto";
|
|
4142
|
+
}
|
|
4143
|
+
}
|
|
4144
|
+
|
|
4145
|
+
// APPLY button handler
|
|
4146
|
+
applyBtn.addEventListener("click", async function() {
|
|
4147
|
+
var provider = select.value;
|
|
4148
|
+
applyBtn.disabled = true;
|
|
4149
|
+
applyBtn.textContent = "...";
|
|
4150
|
+
|
|
4151
|
+
try {
|
|
4152
|
+
var res = await fetch("/api/set-ai-provider", {
|
|
4153
|
+
method: "POST",
|
|
4154
|
+
headers: { "Content-Type": "application/json" },
|
|
4155
|
+
body: JSON.stringify({ provider: provider }),
|
|
4156
|
+
});
|
|
4157
|
+
var data = await res.json();
|
|
4158
|
+
if (data.success) {
|
|
4159
|
+
applyBtn.textContent = "OK";
|
|
4160
|
+
applyBtn.classList.add("success");
|
|
4161
|
+
setTimeout(function() {
|
|
4162
|
+
applyBtn.textContent = "APPLY";
|
|
4163
|
+
applyBtn.classList.remove("success");
|
|
4164
|
+
}, 1500);
|
|
4165
|
+
// Refresh AI keys modal active display if visible
|
|
4166
|
+
var activeEl = document.getElementById("ai-keys-active");
|
|
4167
|
+
if (activeEl && data.activeProvider) {
|
|
4168
|
+
if (data.activeProvider !== "disabled") {
|
|
4169
|
+
activeEl.textContent = "Active: " + data.activeProvider;
|
|
4170
|
+
activeEl.style.color = "";
|
|
4171
|
+
} else {
|
|
4172
|
+
activeEl.textContent = "No AI provider configured";
|
|
4173
|
+
activeEl.style.color = "var(--text-secondary)";
|
|
4174
|
+
}
|
|
4175
|
+
}
|
|
4176
|
+
} else {
|
|
4177
|
+
applyBtn.textContent = "FAIL";
|
|
4178
|
+
setTimeout(function() { applyBtn.textContent = "APPLY"; }, 1500);
|
|
4179
|
+
}
|
|
4180
|
+
} catch {
|
|
4181
|
+
applyBtn.textContent = "ERR";
|
|
4182
|
+
setTimeout(function() { applyBtn.textContent = "APPLY"; }, 1500);
|
|
4183
|
+
}
|
|
4184
|
+
applyBtn.disabled = false;
|
|
4185
|
+
});
|
|
4186
|
+
|
|
4187
|
+
// Load initial state
|
|
4188
|
+
refreshSelector();
|
|
4189
|
+
|
|
4190
|
+
// Expose refresh for AI Keys modal to call after key changes
|
|
4191
|
+
window._refreshAIProviderSelector = refreshSelector;
|
|
4192
|
+
}
|
|
@@ -22,6 +22,13 @@
|
|
|
22
22
|
<span id="license-badge" class="license-badge free">FREE</span>
|
|
23
23
|
<button id="btn-license" class="top-btn license-btn">LICENSE</button>
|
|
24
24
|
<button id="btn-ai-keys" class="top-btn ai-keys-btn">AI</button>
|
|
25
|
+
<select id="ai-provider-select" title="Select AI provider">
|
|
26
|
+
<option value="auto">AUTO</option>
|
|
27
|
+
<option value="gemini">GEMINI</option>
|
|
28
|
+
<option value="openai">OPENAI</option>
|
|
29
|
+
<option value="anthropic">ANTHROPIC</option>
|
|
30
|
+
</select>
|
|
31
|
+
<button id="btn-ai-apply" class="top-btn ai-apply-btn">APPLY</button>
|
|
25
32
|
</div>
|
|
26
33
|
<div class="project-selector">
|
|
27
34
|
<span id="current-project" class="project-path">Loading...</span>
|
|
@@ -2066,6 +2066,54 @@ main {
|
|
|
2066
2066
|
letter-spacing: 1.5px;
|
|
2067
2067
|
}
|
|
2068
2068
|
|
|
2069
|
+
/* AI Provider Selector */
|
|
2070
|
+
#ai-provider-select {
|
|
2071
|
+
padding: 4px 8px;
|
|
2072
|
+
background: rgba(0,0,0,0.5);
|
|
2073
|
+
color: var(--text-primary);
|
|
2074
|
+
border: 1px solid var(--border);
|
|
2075
|
+
border-radius: 2px;
|
|
2076
|
+
font-family: inherit;
|
|
2077
|
+
font-size: 10px;
|
|
2078
|
+
letter-spacing: 1.5px;
|
|
2079
|
+
cursor: pointer;
|
|
2080
|
+
outline: none;
|
|
2081
|
+
transition: all 0.2s;
|
|
2082
|
+
margin-left: 4px;
|
|
2083
|
+
}
|
|
2084
|
+
#ai-provider-select:hover,
|
|
2085
|
+
#ai-provider-select:focus {
|
|
2086
|
+
border-color: var(--accent);
|
|
2087
|
+
box-shadow: 0 0 8px rgba(0,212,255,0.15);
|
|
2088
|
+
}
|
|
2089
|
+
#ai-provider-select option {
|
|
2090
|
+
background: var(--bg-secondary);
|
|
2091
|
+
color: var(--text-primary);
|
|
2092
|
+
font-family: inherit;
|
|
2093
|
+
padding: 4px 8px;
|
|
2094
|
+
}
|
|
2095
|
+
#ai-provider-select option:disabled {
|
|
2096
|
+
color: var(--text-secondary);
|
|
2097
|
+
opacity: 0.4;
|
|
2098
|
+
}
|
|
2099
|
+
|
|
2100
|
+
.ai-apply-btn {
|
|
2101
|
+
font-size: 9px !important;
|
|
2102
|
+
padding: 3px 10px !important;
|
|
2103
|
+
letter-spacing: 1.5px;
|
|
2104
|
+
color: var(--accent) !important;
|
|
2105
|
+
border-color: var(--accent-dim) !important;
|
|
2106
|
+
margin-left: 2px;
|
|
2107
|
+
}
|
|
2108
|
+
.ai-apply-btn:hover {
|
|
2109
|
+
background: rgba(0,212,255,0.08) !important;
|
|
2110
|
+
border-color: var(--accent) !important;
|
|
2111
|
+
}
|
|
2112
|
+
.ai-apply-btn.success {
|
|
2113
|
+
color: var(--risk-low) !important;
|
|
2114
|
+
border-color: var(--risk-low) !important;
|
|
2115
|
+
}
|
|
2116
|
+
|
|
2069
2117
|
/* ═══════════════════════════════════════════ */
|
|
2070
2118
|
/* AI Keys Modal */
|
|
2071
2119
|
/* ═══════════════════════════════════════════ */
|
package/dist/web/server.d.ts
CHANGED
|
@@ -55,4 +55,9 @@ export declare function createWebServer(getGraphFn: () => DependencyGraph, initi
|
|
|
55
55
|
openai: boolean;
|
|
56
56
|
anthropic: boolean;
|
|
57
57
|
};
|
|
58
|
+
forced: string | null;
|
|
59
|
+
}, setAIProviderFn?: (provider: string) => {
|
|
60
|
+
success: boolean;
|
|
61
|
+
activeProvider: string;
|
|
62
|
+
forced: string | null;
|
|
58
63
|
}): WebServerHandle;
|
package/dist/web/server.js
CHANGED
|
@@ -227,7 +227,7 @@ function acknowledgeWarnings() {
|
|
|
227
227
|
function getAllWarnings() {
|
|
228
228
|
return [...warningStore];
|
|
229
229
|
}
|
|
230
|
-
function createWebServer(getGraphFn, initialFileCache, switchProjectFn, getProjectRoot, getPackageName, getLicenseStatus, hasAIKeyFn, setLicenseKeyFn, setAIKeyFn, getAIInfoFn) {
|
|
230
|
+
function createWebServer(getGraphFn, initialFileCache, switchProjectFn, getProjectRoot, getPackageName, getLicenseStatus, hasAIKeyFn, setLicenseKeyFn, setAIKeyFn, getAIInfoFn, setAIProviderFn) {
|
|
231
231
|
const app = (0, express_1.default)();
|
|
232
232
|
app.use(express_1.default.json());
|
|
233
233
|
/** Check if current license is Pro (includes pro_trial) */
|
|
@@ -743,7 +743,7 @@ function createWebServer(getGraphFn, initialFileCache, switchProjectFn, getProje
|
|
|
743
743
|
const maskedKey = rawKey.length > 10
|
|
744
744
|
? rawKey.substring(0, 9) + "····" + rawKey.substring(rawKey.length - 4)
|
|
745
745
|
: "";
|
|
746
|
-
const aiInfo = getAIInfoFn ? getAIInfoFn() : { activeProvider: "disabled", configured: { gemini: false, openai: false, anthropic: false } };
|
|
746
|
+
const aiInfo = getAIInfoFn ? getAIInfoFn() : { activeProvider: "disabled", configured: { gemini: false, openai: false, anthropic: false }, forced: null };
|
|
747
747
|
res.json({
|
|
748
748
|
projectRoot: getProjectRoot ? getProjectRoot() : graph.projectRoot,
|
|
749
749
|
packageName: getPackageName ? getPackageName() : "",
|
|
@@ -758,6 +758,7 @@ function createWebServer(getGraphFn, initialFileCache, switchProjectFn, getProje
|
|
|
758
758
|
sykeVersion,
|
|
759
759
|
aiProvider: aiInfo.activeProvider,
|
|
760
760
|
aiKeys: aiInfo.configured,
|
|
761
|
+
aiProviderForced: aiInfo.forced,
|
|
761
762
|
});
|
|
762
763
|
});
|
|
763
764
|
// POST /api/set-license-key — Set or remove license key via dashboard
|
|
@@ -794,6 +795,25 @@ function createWebServer(getGraphFn, initialFileCache, switchProjectFn, getProje
|
|
|
794
795
|
res.status(500).json({ success: false, error: err.message || "Unknown error" });
|
|
795
796
|
}
|
|
796
797
|
});
|
|
798
|
+
// POST /api/set-ai-provider — Set or clear forced AI provider
|
|
799
|
+
app.post("/api/set-ai-provider", (req, res) => {
|
|
800
|
+
if (!setAIProviderFn) {
|
|
801
|
+
res.status(501).json({ success: false, error: "Not supported" });
|
|
802
|
+
return;
|
|
803
|
+
}
|
|
804
|
+
const { provider } = req.body;
|
|
805
|
+
if (!provider || !["gemini", "openai", "anthropic", "auto"].includes(provider)) {
|
|
806
|
+
res.status(400).json({ success: false, error: "provider must be gemini, openai, anthropic, or auto" });
|
|
807
|
+
return;
|
|
808
|
+
}
|
|
809
|
+
try {
|
|
810
|
+
const result = setAIProviderFn(provider);
|
|
811
|
+
res.json(result);
|
|
812
|
+
}
|
|
813
|
+
catch (err) {
|
|
814
|
+
res.status(500).json({ success: false, error: err.message || "Unknown error" });
|
|
815
|
+
}
|
|
816
|
+
});
|
|
797
817
|
// GET /api/browse-dirs — List subdirectories for folder browser
|
|
798
818
|
app.get("/api/browse-dirs", (req, res) => {
|
|
799
819
|
const dirPath = req.query.path || (process.platform === "win32" ? "C:\\" : "/");
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@syke1/mcp-server",
|
|
3
|
-
"version": "1.4.
|
|
3
|
+
"version": "1.4.12",
|
|
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",
|