@syke1/mcp-server 1.4.5 → 1.4.6
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/ai/provider.d.ts +5 -0
- package/dist/ai/provider.js +8 -0
- package/dist/index.js +28 -0
- package/dist/web/public/app.js +113 -0
- package/dist/web/public/index.html +34 -0
- package/dist/web/public/style.css +148 -0
- package/dist/web/server.d.ts +16 -1
- package/dist/web/server.js +23 -1
- package/package.json +1 -1
package/dist/ai/provider.d.ts
CHANGED
|
@@ -15,6 +15,11 @@ export interface AIProvider {
|
|
|
15
15
|
* 2. Auto-select: GEMINI_KEY > OPENAI_KEY > ANTHROPIC_KEY
|
|
16
16
|
*/
|
|
17
17
|
export declare function getAIProvider(): AIProvider | null;
|
|
18
|
+
/**
|
|
19
|
+
* Reset the cached provider so the next getAIProvider() call re-evaluates config.
|
|
20
|
+
* Call this after changing API keys at runtime.
|
|
21
|
+
*/
|
|
22
|
+
export declare function resetAIProvider(): void;
|
|
18
23
|
/**
|
|
19
24
|
* Human-readable name for the active AI provider (for logs/UI).
|
|
20
25
|
*/
|
package/dist/ai/provider.js
CHANGED
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
*/
|
|
6
6
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
7
|
exports.getAIProvider = getAIProvider;
|
|
8
|
+
exports.resetAIProvider = resetAIProvider;
|
|
8
9
|
exports.getProviderName = getProviderName;
|
|
9
10
|
const generative_ai_1 = require("@google/generative-ai");
|
|
10
11
|
const config_1 = require("../config");
|
|
@@ -169,6 +170,13 @@ function getAIProvider() {
|
|
|
169
170
|
}
|
|
170
171
|
return cachedProvider;
|
|
171
172
|
}
|
|
173
|
+
/**
|
|
174
|
+
* Reset the cached provider so the next getAIProvider() call re-evaluates config.
|
|
175
|
+
* Call this after changing API keys at runtime.
|
|
176
|
+
*/
|
|
177
|
+
function resetAIProvider() {
|
|
178
|
+
cachedProvider = undefined;
|
|
179
|
+
}
|
|
172
180
|
/**
|
|
173
181
|
* Human-readable name for the active AI provider (for logs/UI).
|
|
174
182
|
*/
|
package/dist/index.js
CHANGED
|
@@ -587,6 +587,34 @@ async function main() {
|
|
|
587
587
|
licenseStatus = { plan: "free", source: "default" };
|
|
588
588
|
return { success: true, plan: "free" };
|
|
589
589
|
}
|
|
590
|
+
},
|
|
591
|
+
// setAIKeyFn
|
|
592
|
+
(provider, key) => {
|
|
593
|
+
const map = { gemini: "geminiKey", openai: "openaiKey", anthropic: "anthropicKey" };
|
|
594
|
+
const configKey = map[provider];
|
|
595
|
+
if (configKey) {
|
|
596
|
+
(0, config_1.setConfig)(configKey, key);
|
|
597
|
+
(0, provider_1.resetAIProvider)();
|
|
598
|
+
}
|
|
599
|
+
const gemini = !!(0, config_1.getConfig)("geminiKey", "GEMINI_KEY");
|
|
600
|
+
const openai = !!(0, config_1.getConfig)("openaiKey", "OPENAI_KEY");
|
|
601
|
+
const anthropic = !!(0, config_1.getConfig)("anthropicKey", "ANTHROPIC_KEY");
|
|
602
|
+
return {
|
|
603
|
+
success: true,
|
|
604
|
+
activeProvider: (0, provider_1.getProviderName)(),
|
|
605
|
+
configured: { gemini, openai, anthropic },
|
|
606
|
+
};
|
|
607
|
+
},
|
|
608
|
+
// getAIInfoFn
|
|
609
|
+
() => {
|
|
610
|
+
return {
|
|
611
|
+
activeProvider: (0, provider_1.getProviderName)(),
|
|
612
|
+
configured: {
|
|
613
|
+
gemini: !!(0, config_1.getConfig)("geminiKey", "GEMINI_KEY"),
|
|
614
|
+
openai: !!(0, config_1.getConfig)("openaiKey", "OPENAI_KEY"),
|
|
615
|
+
anthropic: !!(0, config_1.getConfig)("anthropicKey", "ANTHROPIC_KEY"),
|
|
616
|
+
},
|
|
617
|
+
};
|
|
590
618
|
});
|
|
591
619
|
webServerHandle = { setFileCache: setWebFileCache };
|
|
592
620
|
webApp.listen(WEB_PORT, () => {
|
package/dist/web/public/app.js
CHANGED
|
@@ -464,6 +464,7 @@ document.addEventListener("DOMContentLoaded", async () => {
|
|
|
464
464
|
setupSettings();
|
|
465
465
|
setupProjectModal();
|
|
466
466
|
setupLicenseModal();
|
|
467
|
+
setupAIKeysModal();
|
|
467
468
|
setupFileTree();
|
|
468
469
|
initSSE();
|
|
469
470
|
startHealthCheck();
|
|
@@ -3974,3 +3975,115 @@ function setupProjectModal() {
|
|
|
3974
3975
|
if (e.target === modal) modal.classList.add("hidden");
|
|
3975
3976
|
});
|
|
3976
3977
|
}
|
|
3978
|
+
|
|
3979
|
+
// ══════════════════════════════════════════════════════════════
|
|
3980
|
+
// AI KEYS MODAL
|
|
3981
|
+
// ══════════════════════════════════════════════════════════════
|
|
3982
|
+
function setupAIKeysModal() {
|
|
3983
|
+
const btn = document.getElementById("btn-ai-keys");
|
|
3984
|
+
const modal = document.getElementById("ai-keys-modal");
|
|
3985
|
+
const closeBtn = document.getElementById("btn-ai-keys-close");
|
|
3986
|
+
const activeEl = document.getElementById("ai-keys-active");
|
|
3987
|
+
if (!btn || !modal) return;
|
|
3988
|
+
|
|
3989
|
+
function updateStatus(row, isConfigured, isActive) {
|
|
3990
|
+
const statusEl = row.querySelector(".ai-key-status");
|
|
3991
|
+
if (isActive) {
|
|
3992
|
+
statusEl.textContent = "ACTIVE";
|
|
3993
|
+
statusEl.className = "ai-key-status active";
|
|
3994
|
+
} else if (isConfigured) {
|
|
3995
|
+
statusEl.textContent = "CONFIGURED";
|
|
3996
|
+
statusEl.className = "ai-key-status configured";
|
|
3997
|
+
} else {
|
|
3998
|
+
statusEl.textContent = "---";
|
|
3999
|
+
statusEl.className = "ai-key-status none";
|
|
4000
|
+
}
|
|
4001
|
+
}
|
|
4002
|
+
|
|
4003
|
+
function updateAll(aiKeys, activeProvider) {
|
|
4004
|
+
const rows = modal.querySelectorAll(".ai-key-row");
|
|
4005
|
+
rows.forEach(function(row) {
|
|
4006
|
+
const provider = row.dataset.provider;
|
|
4007
|
+
const configured = aiKeys[provider] || false;
|
|
4008
|
+
const isActive = configured && activeProvider.toLowerCase().includes(provider);
|
|
4009
|
+
updateStatus(row, configured, isActive);
|
|
4010
|
+
});
|
|
4011
|
+
if (activeProvider && activeProvider !== "disabled") {
|
|
4012
|
+
activeEl.textContent = "Active: " + activeProvider;
|
|
4013
|
+
} else {
|
|
4014
|
+
activeEl.textContent = "No AI provider configured";
|
|
4015
|
+
activeEl.style.color = "var(--text-secondary)";
|
|
4016
|
+
}
|
|
4017
|
+
}
|
|
4018
|
+
|
|
4019
|
+
async function openModal() {
|
|
4020
|
+
modal.classList.remove("hidden");
|
|
4021
|
+
// Clear inputs
|
|
4022
|
+
modal.querySelectorAll(".ai-key-input").forEach(function(inp) { inp.value = ""; });
|
|
4023
|
+
// Fetch current state
|
|
4024
|
+
try {
|
|
4025
|
+
const res = await fetch("/api/project-info");
|
|
4026
|
+
const info = await res.json();
|
|
4027
|
+
updateAll(info.aiKeys || {}, info.aiProvider || "disabled");
|
|
4028
|
+
} catch {
|
|
4029
|
+
activeEl.textContent = "Failed to fetch status";
|
|
4030
|
+
}
|
|
4031
|
+
}
|
|
4032
|
+
|
|
4033
|
+
function closeModal() {
|
|
4034
|
+
modal.classList.add("hidden");
|
|
4035
|
+
}
|
|
4036
|
+
|
|
4037
|
+
btn.addEventListener("click", openModal);
|
|
4038
|
+
closeBtn.addEventListener("click", closeModal);
|
|
4039
|
+
modal.addEventListener("click", function(e) { if (e.target === modal) closeModal(); });
|
|
4040
|
+
|
|
4041
|
+
// SET button handlers
|
|
4042
|
+
modal.querySelectorAll(".ai-key-row").forEach(function(row) {
|
|
4043
|
+
const setBtn = row.querySelector(".ai-key-set-btn");
|
|
4044
|
+
const input = row.querySelector(".ai-key-input");
|
|
4045
|
+
const provider = row.dataset.provider;
|
|
4046
|
+
|
|
4047
|
+
setBtn.addEventListener("click", async function() {
|
|
4048
|
+
const key = input.value.trim();
|
|
4049
|
+
setBtn.disabled = true;
|
|
4050
|
+
setBtn.textContent = "...";
|
|
4051
|
+
|
|
4052
|
+
try {
|
|
4053
|
+
const res = await fetch("/api/set-ai-key", {
|
|
4054
|
+
method: "POST",
|
|
4055
|
+
headers: { "Content-Type": "application/json" },
|
|
4056
|
+
body: JSON.stringify({ provider: provider, key: key || null }),
|
|
4057
|
+
});
|
|
4058
|
+
const data = await res.json();
|
|
4059
|
+
if (data.success) {
|
|
4060
|
+
updateAll(data.configured, data.activeProvider);
|
|
4061
|
+
input.value = "";
|
|
4062
|
+
if (key) {
|
|
4063
|
+
input.placeholder = "****" + key.slice(-4);
|
|
4064
|
+
} else {
|
|
4065
|
+
var placeholders = { gemini: "AIzaSy...", openai: "sk-...", anthropic: "sk-ant-..." };
|
|
4066
|
+
input.placeholder = placeholders[provider] || "";
|
|
4067
|
+
}
|
|
4068
|
+
}
|
|
4069
|
+
} catch (err) {
|
|
4070
|
+
var statusEl = row.querySelector(".ai-key-status");
|
|
4071
|
+
statusEl.textContent = "ERROR";
|
|
4072
|
+
statusEl.className = "ai-key-status";
|
|
4073
|
+
statusEl.style.color = "#ff5f57";
|
|
4074
|
+
}
|
|
4075
|
+
setBtn.disabled = false;
|
|
4076
|
+
setBtn.textContent = "SET";
|
|
4077
|
+
});
|
|
4078
|
+
|
|
4079
|
+
input.addEventListener("keydown", function(e) {
|
|
4080
|
+
if (e.key === "Enter") setBtn.click();
|
|
4081
|
+
});
|
|
4082
|
+
});
|
|
4083
|
+
|
|
4084
|
+
document.addEventListener("keydown", function(e) {
|
|
4085
|
+
if (e.key === "Escape" && !modal.classList.contains("hidden")) {
|
|
4086
|
+
closeModal();
|
|
4087
|
+
}
|
|
4088
|
+
});
|
|
4089
|
+
}
|
|
@@ -21,6 +21,7 @@
|
|
|
21
21
|
<span id="sse-status" class="sse-indicator offline">OFFLINE</span>
|
|
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
|
+
<button id="btn-ai-keys" class="top-btn ai-keys-btn">AI</button>
|
|
24
25
|
</div>
|
|
25
26
|
<div class="project-selector">
|
|
26
27
|
<span id="current-project" class="project-path">Loading...</span>
|
|
@@ -455,6 +456,39 @@
|
|
|
455
456
|
</div>
|
|
456
457
|
</div>
|
|
457
458
|
|
|
459
|
+
<!-- AI Keys Modal -->
|
|
460
|
+
<div id="ai-keys-modal" class="hidden">
|
|
461
|
+
<div class="ai-keys-modal-panel">
|
|
462
|
+
<h3>AI PROVIDER KEYS</h3>
|
|
463
|
+
<p class="ai-keys-modal-desc">Configure API keys to enable AI analysis.</p>
|
|
464
|
+
<div class="ai-keys-rows">
|
|
465
|
+
<div class="ai-key-row" data-provider="gemini">
|
|
466
|
+
<span class="ai-key-label">GEMINI</span>
|
|
467
|
+
<input type="password" class="ai-key-input" placeholder="AIzaSy..." spellcheck="false" autocomplete="off">
|
|
468
|
+
<button class="ai-key-set-btn">SET</button>
|
|
469
|
+
<span class="ai-key-status"></span>
|
|
470
|
+
</div>
|
|
471
|
+
<div class="ai-key-row" data-provider="openai">
|
|
472
|
+
<span class="ai-key-label">OPENAI</span>
|
|
473
|
+
<input type="password" class="ai-key-input" placeholder="sk-..." spellcheck="false" autocomplete="off">
|
|
474
|
+
<button class="ai-key-set-btn">SET</button>
|
|
475
|
+
<span class="ai-key-status"></span>
|
|
476
|
+
</div>
|
|
477
|
+
<div class="ai-key-row" data-provider="anthropic">
|
|
478
|
+
<span class="ai-key-label">ANTHROPIC</span>
|
|
479
|
+
<input type="password" class="ai-key-input" placeholder="sk-ant-..." spellcheck="false" autocomplete="off">
|
|
480
|
+
<button class="ai-key-set-btn">SET</button>
|
|
481
|
+
<span class="ai-key-status"></span>
|
|
482
|
+
</div>
|
|
483
|
+
</div>
|
|
484
|
+
<div id="ai-keys-active" class="ai-keys-active"></div>
|
|
485
|
+
<div class="ai-keys-modal-actions">
|
|
486
|
+
<button id="btn-ai-keys-close">CLOSE</button>
|
|
487
|
+
</div>
|
|
488
|
+
<p class="ai-keys-priority">Priority: Gemini > OpenAI > Anthropic</p>
|
|
489
|
+
</div>
|
|
490
|
+
</div>
|
|
491
|
+
|
|
458
492
|
<!-- Bottom status bar -->
|
|
459
493
|
<div id="bottom-bar">
|
|
460
494
|
<span id="bottom-info">SYKE v--- · ---</span>
|
|
@@ -2060,6 +2060,154 @@ main {
|
|
|
2060
2060
|
letter-spacing: 1.5px;
|
|
2061
2061
|
}
|
|
2062
2062
|
|
|
2063
|
+
.ai-keys-btn {
|
|
2064
|
+
font-size: 9px !important;
|
|
2065
|
+
padding: 2px 8px !important;
|
|
2066
|
+
letter-spacing: 1.5px;
|
|
2067
|
+
}
|
|
2068
|
+
|
|
2069
|
+
/* ═══════════════════════════════════════════ */
|
|
2070
|
+
/* AI Keys Modal */
|
|
2071
|
+
/* ═══════════════════════════════════════════ */
|
|
2072
|
+
#ai-keys-modal {
|
|
2073
|
+
position: fixed;
|
|
2074
|
+
inset: 0;
|
|
2075
|
+
background: rgba(5,10,24,0.85);
|
|
2076
|
+
z-index: 400;
|
|
2077
|
+
display: flex;
|
|
2078
|
+
align-items: center;
|
|
2079
|
+
justify-content: center;
|
|
2080
|
+
backdrop-filter: blur(4px);
|
|
2081
|
+
}
|
|
2082
|
+
#ai-keys-modal.hidden { display: none; }
|
|
2083
|
+
|
|
2084
|
+
.ai-keys-modal-panel {
|
|
2085
|
+
background: var(--bg-secondary);
|
|
2086
|
+
border: 1px solid var(--accent-dim);
|
|
2087
|
+
border-radius: 6px;
|
|
2088
|
+
padding: 24px 32px;
|
|
2089
|
+
min-width: 460px;
|
|
2090
|
+
max-width: 520px;
|
|
2091
|
+
box-shadow: var(--glow-cyan), 0 16px 64px rgba(0,0,0,0.5);
|
|
2092
|
+
}
|
|
2093
|
+
.ai-keys-modal-panel h3 {
|
|
2094
|
+
font-size: 12px;
|
|
2095
|
+
color: var(--accent);
|
|
2096
|
+
letter-spacing: 3px;
|
|
2097
|
+
margin-bottom: 8px;
|
|
2098
|
+
}
|
|
2099
|
+
.ai-keys-modal-desc {
|
|
2100
|
+
font-size: 11px;
|
|
2101
|
+
color: var(--text-secondary);
|
|
2102
|
+
margin-bottom: 16px;
|
|
2103
|
+
}
|
|
2104
|
+
.ai-keys-rows {
|
|
2105
|
+
display: flex;
|
|
2106
|
+
flex-direction: column;
|
|
2107
|
+
gap: 8px;
|
|
2108
|
+
margin-bottom: 14px;
|
|
2109
|
+
}
|
|
2110
|
+
.ai-key-row {
|
|
2111
|
+
display: flex;
|
|
2112
|
+
align-items: center;
|
|
2113
|
+
gap: 8px;
|
|
2114
|
+
}
|
|
2115
|
+
.ai-key-label {
|
|
2116
|
+
font-size: 10px;
|
|
2117
|
+
letter-spacing: 2px;
|
|
2118
|
+
color: var(--text-secondary);
|
|
2119
|
+
width: 80px;
|
|
2120
|
+
flex-shrink: 0;
|
|
2121
|
+
}
|
|
2122
|
+
.ai-key-input {
|
|
2123
|
+
flex: 1;
|
|
2124
|
+
padding: 7px 10px;
|
|
2125
|
+
background: rgba(0,0,0,0.5);
|
|
2126
|
+
border: 1px solid var(--border);
|
|
2127
|
+
border-radius: 3px;
|
|
2128
|
+
color: var(--text-primary);
|
|
2129
|
+
font-family: inherit;
|
|
2130
|
+
font-size: 12px;
|
|
2131
|
+
letter-spacing: 1px;
|
|
2132
|
+
outline: none;
|
|
2133
|
+
transition: border-color 0.2s;
|
|
2134
|
+
}
|
|
2135
|
+
.ai-key-input:focus {
|
|
2136
|
+
border-color: var(--accent);
|
|
2137
|
+
box-shadow: 0 0 8px rgba(0,212,255,0.15);
|
|
2138
|
+
}
|
|
2139
|
+
.ai-key-input::placeholder {
|
|
2140
|
+
color: var(--text-secondary);
|
|
2141
|
+
font-size: 11px;
|
|
2142
|
+
opacity: 0.5;
|
|
2143
|
+
}
|
|
2144
|
+
.ai-key-set-btn {
|
|
2145
|
+
padding: 6px 12px;
|
|
2146
|
+
border: 1px solid var(--accent-dim);
|
|
2147
|
+
border-radius: 3px;
|
|
2148
|
+
background: transparent;
|
|
2149
|
+
color: var(--accent);
|
|
2150
|
+
font-family: inherit;
|
|
2151
|
+
font-size: 10px;
|
|
2152
|
+
letter-spacing: 2px;
|
|
2153
|
+
cursor: pointer;
|
|
2154
|
+
transition: all 0.2s;
|
|
2155
|
+
flex-shrink: 0;
|
|
2156
|
+
}
|
|
2157
|
+
.ai-key-set-btn:hover {
|
|
2158
|
+
background: rgba(0,212,255,0.08);
|
|
2159
|
+
border-color: var(--accent);
|
|
2160
|
+
}
|
|
2161
|
+
.ai-key-status {
|
|
2162
|
+
font-size: 9px;
|
|
2163
|
+
letter-spacing: 1px;
|
|
2164
|
+
width: 70px;
|
|
2165
|
+
text-align: center;
|
|
2166
|
+
flex-shrink: 0;
|
|
2167
|
+
}
|
|
2168
|
+
.ai-key-status.active {
|
|
2169
|
+
color: var(--risk-low);
|
|
2170
|
+
}
|
|
2171
|
+
.ai-key-status.configured {
|
|
2172
|
+
color: var(--text-secondary);
|
|
2173
|
+
}
|
|
2174
|
+
.ai-key-status.none {
|
|
2175
|
+
color: var(--text-secondary);
|
|
2176
|
+
opacity: 0.4;
|
|
2177
|
+
}
|
|
2178
|
+
.ai-keys-active {
|
|
2179
|
+
font-size: 11px;
|
|
2180
|
+
color: var(--risk-low);
|
|
2181
|
+
margin-bottom: 14px;
|
|
2182
|
+
min-height: 18px;
|
|
2183
|
+
}
|
|
2184
|
+
.ai-keys-modal-actions {
|
|
2185
|
+
display: flex;
|
|
2186
|
+
gap: 8px;
|
|
2187
|
+
margin-bottom: 10px;
|
|
2188
|
+
}
|
|
2189
|
+
.ai-keys-modal-actions button {
|
|
2190
|
+
padding: 8px 18px;
|
|
2191
|
+
border: 1px solid var(--accent-dim);
|
|
2192
|
+
border-radius: 3px;
|
|
2193
|
+
background: transparent;
|
|
2194
|
+
color: var(--accent);
|
|
2195
|
+
font-family: inherit;
|
|
2196
|
+
font-size: 10px;
|
|
2197
|
+
letter-spacing: 2px;
|
|
2198
|
+
cursor: pointer;
|
|
2199
|
+
transition: all 0.2s;
|
|
2200
|
+
}
|
|
2201
|
+
.ai-keys-modal-actions button:hover {
|
|
2202
|
+
background: rgba(0,212,255,0.08);
|
|
2203
|
+
border-color: var(--accent);
|
|
2204
|
+
}
|
|
2205
|
+
.ai-keys-priority {
|
|
2206
|
+
font-size: 9px;
|
|
2207
|
+
color: var(--text-secondary);
|
|
2208
|
+
opacity: 0.6;
|
|
2209
|
+
}
|
|
2210
|
+
|
|
2063
2211
|
/* ═══════════════════════════════════════════ */
|
|
2064
2212
|
/* Project Switch Modal */
|
|
2065
2213
|
/* ═══════════════════════════════════════════ */
|
package/dist/web/server.d.ts
CHANGED
|
@@ -40,4 +40,19 @@ export declare function createWebServer(getGraphFn: () => DependencyGraph, initi
|
|
|
40
40
|
plan?: string;
|
|
41
41
|
expiresAt?: string;
|
|
42
42
|
error?: string;
|
|
43
|
-
}
|
|
43
|
+
}>, setAIKeyFn?: (provider: string, key: string | null) => {
|
|
44
|
+
success: boolean;
|
|
45
|
+
activeProvider: string;
|
|
46
|
+
configured: {
|
|
47
|
+
gemini: boolean;
|
|
48
|
+
openai: boolean;
|
|
49
|
+
anthropic: boolean;
|
|
50
|
+
};
|
|
51
|
+
}, getAIInfoFn?: () => {
|
|
52
|
+
activeProvider: string;
|
|
53
|
+
configured: {
|
|
54
|
+
gemini: boolean;
|
|
55
|
+
openai: boolean;
|
|
56
|
+
anthropic: boolean;
|
|
57
|
+
};
|
|
58
|
+
}): 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) {
|
|
230
|
+
function createWebServer(getGraphFn, initialFileCache, switchProjectFn, getProjectRoot, getPackageName, getLicenseStatus, hasAIKeyFn, setLicenseKeyFn, setAIKeyFn, getAIInfoFn) {
|
|
231
231
|
const app = (0, express_1.default)();
|
|
232
232
|
app.use(express_1.default.json());
|
|
233
233
|
// Serve static files from public/
|
|
@@ -745,6 +745,7 @@ function createWebServer(getGraphFn, initialFileCache, switchProjectFn, getProje
|
|
|
745
745
|
const maskedKey = rawKey.length > 10
|
|
746
746
|
? rawKey.substring(0, 9) + "····" + rawKey.substring(rawKey.length - 4)
|
|
747
747
|
: "";
|
|
748
|
+
const aiInfo = getAIInfoFn ? getAIInfoFn() : { activeProvider: "disabled", configured: { gemini: false, openai: false, anthropic: false } };
|
|
748
749
|
res.json({
|
|
749
750
|
projectRoot: getProjectRoot ? getProjectRoot() : graph.projectRoot,
|
|
750
751
|
packageName: getPackageName ? getPackageName() : "",
|
|
@@ -757,6 +758,8 @@ function createWebServer(getGraphFn, initialFileCache, switchProjectFn, getProje
|
|
|
757
758
|
licenseKey: maskedKey,
|
|
758
759
|
freeFileLimit: 50,
|
|
759
760
|
sykeVersion,
|
|
761
|
+
aiProvider: aiInfo.activeProvider,
|
|
762
|
+
aiKeys: aiInfo.configured,
|
|
760
763
|
});
|
|
761
764
|
});
|
|
762
765
|
// POST /api/set-license-key — Set or remove license key via dashboard
|
|
@@ -774,6 +777,25 @@ function createWebServer(getGraphFn, initialFileCache, switchProjectFn, getProje
|
|
|
774
777
|
res.status(500).json({ success: false, error: err.message || "Unknown error" });
|
|
775
778
|
}
|
|
776
779
|
});
|
|
780
|
+
// POST /api/set-ai-key — Set or remove an AI provider API key
|
|
781
|
+
app.post("/api/set-ai-key", (req, res) => {
|
|
782
|
+
if (!setAIKeyFn) {
|
|
783
|
+
res.status(501).json({ success: false, error: "Not supported" });
|
|
784
|
+
return;
|
|
785
|
+
}
|
|
786
|
+
const { provider, key } = req.body;
|
|
787
|
+
if (!provider || !["gemini", "openai", "anthropic"].includes(provider)) {
|
|
788
|
+
res.status(400).json({ success: false, error: "provider must be gemini, openai, or anthropic" });
|
|
789
|
+
return;
|
|
790
|
+
}
|
|
791
|
+
try {
|
|
792
|
+
const result = setAIKeyFn(provider, key || null);
|
|
793
|
+
res.json(result);
|
|
794
|
+
}
|
|
795
|
+
catch (err) {
|
|
796
|
+
res.status(500).json({ success: false, error: err.message || "Unknown error" });
|
|
797
|
+
}
|
|
798
|
+
});
|
|
777
799
|
// GET /api/browse-dirs — List subdirectories for folder browser
|
|
778
800
|
app.get("/api/browse-dirs", (req, res) => {
|
|
779
801
|
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.6",
|
|
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",
|