@leadbay/mcp 0.23.5 → 0.23.7
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/CHANGELOG.md +13 -0
- package/dist/bin.js +331 -65
- package/dist/http-server.js +329 -65
- package/dist/installer-electron.js +226 -71
- package/dist/installer-gui.js +225 -70
- package/package.json +1 -1
package/dist/installer-gui.js
CHANGED
|
@@ -1027,7 +1027,157 @@ async function oauthLogin(opts) {
|
|
|
1027
1027
|
}
|
|
1028
1028
|
|
|
1029
1029
|
// installer/installer-gui.ts
|
|
1030
|
-
var VERSION = true ? "0.23.
|
|
1030
|
+
var VERSION = true ? "0.23.7" : "0.0.0-dev";
|
|
1031
|
+
var MESSAGES = {
|
|
1032
|
+
en: {
|
|
1033
|
+
installer: {
|
|
1034
|
+
docTitle: "Leadbay MCP installer",
|
|
1035
|
+
steps: {
|
|
1036
|
+
1: { title: "Connect Leadbay", sub: "Sign in to install Leadbay across your AI agents." },
|
|
1037
|
+
2: { title: "Choose your agents", sub: "Pick where to install Leadbay." },
|
|
1038
|
+
3: { title: "Installing", sub: "Keep this window open until it's done." }
|
|
1039
|
+
},
|
|
1040
|
+
btnSignIn: "Sign in with Leadbay",
|
|
1041
|
+
btnInstall: "Install",
|
|
1042
|
+
btnBack: "Back",
|
|
1043
|
+
btnRefresh: "Refresh",
|
|
1044
|
+
noClientsDetected: "No supported MCP client detected on this machine.",
|
|
1045
|
+
noAgentsDetected: "No supported agents detected.",
|
|
1046
|
+
selectAtLeastOne: "Select at least one agent.",
|
|
1047
|
+
openingSignIn: "Opening Leadbay sign-in in your browser...",
|
|
1048
|
+
oauthFailed: "OAuth login failed.",
|
|
1049
|
+
successInstalled: "MCP successfully installed",
|
|
1050
|
+
noneInstalled: "No agents were installed.",
|
|
1051
|
+
streamDisconnected: "Install stream disconnected.",
|
|
1052
|
+
closeWindow: "You can close this window.",
|
|
1053
|
+
allSet: "All set",
|
|
1054
|
+
somethingWrong: "Something went wrong",
|
|
1055
|
+
badgeManual: "manual",
|
|
1056
|
+
badgeUpdate: "update",
|
|
1057
|
+
badgeInstall: "install"
|
|
1058
|
+
},
|
|
1059
|
+
uninstaller: {
|
|
1060
|
+
docTitle: "Leadbay MCP uninstaller",
|
|
1061
|
+
steps: {
|
|
1062
|
+
1: { title: "Remove Leadbay MCP", sub: "Select the agents to remove Leadbay MCP from." },
|
|
1063
|
+
2: { title: "Removing", sub: "Keep this window open until it's done." }
|
|
1064
|
+
},
|
|
1065
|
+
btnRemove: "Remove selected",
|
|
1066
|
+
btnBack: "Back",
|
|
1067
|
+
btnRefresh: "Refresh",
|
|
1068
|
+
noInstallDetected: "No Leadbay MCP installation detected on this machine.",
|
|
1069
|
+
selectAtLeastOne: "Select at least one agent.",
|
|
1070
|
+
successRemoved: "MCP successfully removed",
|
|
1071
|
+
noneRemoved: "No agents were removed.",
|
|
1072
|
+
streamDisconnected: "Uninstall stream disconnected.",
|
|
1073
|
+
closeWindow: "You can close this window.",
|
|
1074
|
+
allSet: "All set",
|
|
1075
|
+
somethingWrong: "Something went wrong"
|
|
1076
|
+
},
|
|
1077
|
+
server: {
|
|
1078
|
+
loginExpired: "Login expired. Go back and sign in again.",
|
|
1079
|
+
selectAtLeastOne: "Select at least one agent.",
|
|
1080
|
+
noSelectedDetected: "No selected agents were detected on this machine.",
|
|
1081
|
+
installStopped: "Install stopped.",
|
|
1082
|
+
uninstallStopped: "Uninstall stopped.",
|
|
1083
|
+
connectedTo: (label) => `Connected to ${label}.`,
|
|
1084
|
+
toolFlags: (write, telemetry) => `Write tools ${write ? "enabled" : "disabled"}; telemetry ${telemetry ? "enabled" : "disabled"}.`,
|
|
1085
|
+
refreshingDetection: "Refreshing installed-agent detection...",
|
|
1086
|
+
installing: (label) => `Installing ${label}...`,
|
|
1087
|
+
preparingManual: (label) => `Preparing ${label} manual setup...`,
|
|
1088
|
+
removing: (label) => `Removing from ${label}...`,
|
|
1089
|
+
installedSummary: (ok, total) => `${ok}/${total} agent(s) installed, updated, or prepared.`,
|
|
1090
|
+
manualReady: "Manual ChatGPT setup instructions ready.",
|
|
1091
|
+
removedSummary: (ok, total) => `${ok}/${total} agent(s) removed.`,
|
|
1092
|
+
restartClients: "Restart your MCP client(s) to pick up the new server.",
|
|
1093
|
+
followManual: "Follow the manual setup instructions shown above.",
|
|
1094
|
+
completeRemoval: "Restart your MCP client(s) to complete the removal.",
|
|
1095
|
+
loggedInBackend: (region) => `Logged in to ${region.toUpperCase()} backend.`,
|
|
1096
|
+
settingsLine: (write, telemetry) => `Settings: write tools ${write ? "on" : "off"}, telemetry ${telemetry ? "on" : "off"}.`,
|
|
1097
|
+
installSummaryHeader: "Install summary:",
|
|
1098
|
+
noAgentsRemoved: "No agents were removed."
|
|
1099
|
+
}
|
|
1100
|
+
},
|
|
1101
|
+
fr: {
|
|
1102
|
+
installer: {
|
|
1103
|
+
docTitle: "Installateur Leadbay MCP",
|
|
1104
|
+
steps: {
|
|
1105
|
+
1: { title: "Connectez Leadbay", sub: "Connectez-vous pour installer Leadbay sur vos agents IA." },
|
|
1106
|
+
2: { title: "Choisissez vos agents", sub: "Choisissez o\xF9 installer Leadbay." },
|
|
1107
|
+
3: { title: "Installation en cours", sub: "Gardez cette fen\xEAtre ouverte jusqu'\xE0 la fin." }
|
|
1108
|
+
},
|
|
1109
|
+
btnSignIn: "Se connecter avec Leadbay",
|
|
1110
|
+
btnInstall: "Installer",
|
|
1111
|
+
btnBack: "Retour",
|
|
1112
|
+
btnRefresh: "Actualiser",
|
|
1113
|
+
noClientsDetected: "Aucun client MCP compatible d\xE9tect\xE9 sur cette machine.",
|
|
1114
|
+
noAgentsDetected: "Aucun agent compatible d\xE9tect\xE9.",
|
|
1115
|
+
selectAtLeastOne: "S\xE9lectionnez au moins un agent.",
|
|
1116
|
+
openingSignIn: "Ouverture de la connexion Leadbay dans votre navigateur...",
|
|
1117
|
+
oauthFailed: "\xC9chec de la connexion OAuth.",
|
|
1118
|
+
successInstalled: "MCP install\xE9 avec succ\xE8s",
|
|
1119
|
+
noneInstalled: "Aucun agent n'a \xE9t\xE9 install\xE9.",
|
|
1120
|
+
streamDisconnected: "Flux d'installation interrompu.",
|
|
1121
|
+
closeWindow: "Vous pouvez fermer cette fen\xEAtre.",
|
|
1122
|
+
allSet: "Termin\xE9",
|
|
1123
|
+
somethingWrong: "Une erreur est survenue",
|
|
1124
|
+
badgeManual: "manuel",
|
|
1125
|
+
badgeUpdate: "mettre \xE0 jour",
|
|
1126
|
+
badgeInstall: "installer"
|
|
1127
|
+
},
|
|
1128
|
+
uninstaller: {
|
|
1129
|
+
docTitle: "D\xE9sinstallateur Leadbay MCP",
|
|
1130
|
+
steps: {
|
|
1131
|
+
1: { title: "Supprimer Leadbay MCP", sub: "S\xE9lectionnez les agents desquels supprimer Leadbay MCP." },
|
|
1132
|
+
2: { title: "Suppression en cours", sub: "Gardez cette fen\xEAtre ouverte jusqu'\xE0 la fin." }
|
|
1133
|
+
},
|
|
1134
|
+
btnRemove: "Supprimer la s\xE9lection",
|
|
1135
|
+
btnBack: "Retour",
|
|
1136
|
+
btnRefresh: "Actualiser",
|
|
1137
|
+
noInstallDetected: "Aucune installation Leadbay MCP d\xE9tect\xE9e sur cette machine.",
|
|
1138
|
+
selectAtLeastOne: "S\xE9lectionnez au moins un agent.",
|
|
1139
|
+
successRemoved: "MCP supprim\xE9 avec succ\xE8s",
|
|
1140
|
+
noneRemoved: "Aucun agent n'a \xE9t\xE9 supprim\xE9.",
|
|
1141
|
+
streamDisconnected: "Flux de d\xE9sinstallation interrompu.",
|
|
1142
|
+
closeWindow: "Vous pouvez fermer cette fen\xEAtre.",
|
|
1143
|
+
allSet: "Termin\xE9",
|
|
1144
|
+
somethingWrong: "Une erreur est survenue"
|
|
1145
|
+
},
|
|
1146
|
+
server: {
|
|
1147
|
+
loginExpired: "Session expir\xE9e. Revenez en arri\xE8re et reconnectez-vous.",
|
|
1148
|
+
selectAtLeastOne: "S\xE9lectionnez au moins un agent.",
|
|
1149
|
+
noSelectedDetected: "Aucun des agents s\xE9lectionn\xE9s n'a \xE9t\xE9 d\xE9tect\xE9 sur cette machine.",
|
|
1150
|
+
installStopped: "Installation arr\xEAt\xE9e.",
|
|
1151
|
+
uninstallStopped: "D\xE9sinstallation arr\xEAt\xE9e.",
|
|
1152
|
+
connectedTo: (label) => `Connect\xE9 \xE0 ${label}.`,
|
|
1153
|
+
toolFlags: (write, telemetry) => `Outils d'\xE9criture ${write ? "activ\xE9s" : "d\xE9sactiv\xE9s"} ; t\xE9l\xE9m\xE9trie ${telemetry ? "activ\xE9e" : "d\xE9sactiv\xE9e"}.`,
|
|
1154
|
+
refreshingDetection: "Actualisation de la d\xE9tection des agents install\xE9s...",
|
|
1155
|
+
installing: (label) => `Installation de ${label}...`,
|
|
1156
|
+
preparingManual: (label) => `Pr\xE9paration de la configuration manuelle de ${label}...`,
|
|
1157
|
+
removing: (label) => `Suppression de ${label}...`,
|
|
1158
|
+
installedSummary: (ok, total) => `${ok}/${total} agent(s) install\xE9(s), mis \xE0 jour ou pr\xE9par\xE9(s).`,
|
|
1159
|
+
manualReady: "Instructions de configuration manuelle de ChatGPT pr\xEAtes.",
|
|
1160
|
+
removedSummary: (ok, total) => `${ok}/${total} agent(s) supprim\xE9(s).`,
|
|
1161
|
+
restartClients: "Red\xE9marrez votre/vos client(s) MCP pour charger le nouveau serveur.",
|
|
1162
|
+
followManual: "Suivez les instructions de configuration manuelle ci-dessus.",
|
|
1163
|
+
completeRemoval: "Red\xE9marrez votre/vos client(s) MCP pour terminer la suppression.",
|
|
1164
|
+
loggedInBackend: (region) => `Connect\xE9 au backend ${region.toUpperCase()}.`,
|
|
1165
|
+
settingsLine: (write, telemetry) => `Param\xE8tres : outils d'\xE9criture ${write ? "activ\xE9s" : "d\xE9sactiv\xE9s"}, t\xE9l\xE9m\xE9trie ${telemetry ? "activ\xE9e" : "d\xE9sactiv\xE9e"}.`,
|
|
1166
|
+
installSummaryHeader: "R\xE9capitulatif de l'installation :",
|
|
1167
|
+
noAgentsRemoved: "Aucun agent n'a \xE9t\xE9 supprim\xE9."
|
|
1168
|
+
}
|
|
1169
|
+
}
|
|
1170
|
+
};
|
|
1171
|
+
async function detectLocale() {
|
|
1172
|
+
try {
|
|
1173
|
+
return await inferRegionViaStargate({ staging: false }) === "fr" ? "fr" : "en";
|
|
1174
|
+
} catch {
|
|
1175
|
+
return "en";
|
|
1176
|
+
}
|
|
1177
|
+
}
|
|
1178
|
+
function parseLocale(raw) {
|
|
1179
|
+
return raw === "fr" ? "fr" : "en";
|
|
1180
|
+
}
|
|
1031
1181
|
var PORT = Number(process.env.LEADBAY_INSTALLER_PORT ?? 0);
|
|
1032
1182
|
var sessions = /* @__PURE__ */ new Map();
|
|
1033
1183
|
var OAUTH_BASE_URLS = {
|
|
@@ -1176,23 +1326,25 @@ async function install(body) {
|
|
|
1176
1326
|
cleanupSessions();
|
|
1177
1327
|
const session = body.sessionId ? sessions.get(body.sessionId) : void 0;
|
|
1178
1328
|
const clientIds = body.clientIds ?? [];
|
|
1179
|
-
if (!session) return { ok: false, output:
|
|
1180
|
-
if (!clientIds.length) return { ok: false, output:
|
|
1329
|
+
if (!session) return { ok: false, output: MESSAGES.en.server.loginExpired };
|
|
1330
|
+
if (!clientIds.length) return { ok: false, output: MESSAGES.en.server.selectAtLeastOne };
|
|
1331
|
+
const locale = session.region === "fr" ? "fr" : "en";
|
|
1332
|
+
const s = MESSAGES[locale].server;
|
|
1181
1333
|
const detected = await detectClients();
|
|
1182
1334
|
const selected = detected.filter((client) => clientIds.includes(client.id));
|
|
1183
|
-
if (!selected.length) return { ok: false, output:
|
|
1335
|
+
if (!selected.length) return { ok: false, output: s.noSelectedDetected };
|
|
1184
1336
|
const includeWrite = body.includeWrite !== false;
|
|
1185
1337
|
const telemetryEnabled = body.telemetryEnabled !== false;
|
|
1186
1338
|
const results = [];
|
|
1187
1339
|
for (const client of selected) results.push(await installInto(client, session, includeWrite, telemetryEnabled));
|
|
1188
1340
|
const output = [
|
|
1189
|
-
|
|
1190
|
-
|
|
1341
|
+
s.loggedInBackend(session.region),
|
|
1342
|
+
s.settingsLine(includeWrite, telemetryEnabled),
|
|
1191
1343
|
"",
|
|
1192
|
-
|
|
1344
|
+
s.installSummaryHeader,
|
|
1193
1345
|
...results.map((result) => `${result.ok ? "OK" : "ERROR"} ${result.label}: ${result.message}`),
|
|
1194
1346
|
"",
|
|
1195
|
-
|
|
1347
|
+
s.restartClients
|
|
1196
1348
|
].join("\n");
|
|
1197
1349
|
return { ok: results.some((result) => result.ok), output: sanitizeOutput(output), results };
|
|
1198
1350
|
}
|
|
@@ -1207,6 +1359,8 @@ async function streamInstall(url, res, onDone) {
|
|
|
1207
1359
|
const clientIds = (url.searchParams.get("clients") ?? "").split(",").filter(Boolean);
|
|
1208
1360
|
const includeWrite = url.searchParams.get("write") !== "0";
|
|
1209
1361
|
const telemetryEnabled = url.searchParams.get("telemetry") !== "0";
|
|
1362
|
+
const locale = parseLocale(url.searchParams.get("locale"));
|
|
1363
|
+
const s = MESSAGES[locale].server;
|
|
1210
1364
|
const emit = (level, message) => sendSse(res, { level, message: sanitizeOutput(message) });
|
|
1211
1365
|
const abort = (msg) => {
|
|
1212
1366
|
emit("done", msg);
|
|
@@ -1218,29 +1372,29 @@ async function streamInstall(url, res, onDone) {
|
|
|
1218
1372
|
onDone?.();
|
|
1219
1373
|
};
|
|
1220
1374
|
if (!session) {
|
|
1221
|
-
emit("error",
|
|
1222
|
-
abort(
|
|
1375
|
+
emit("error", s.loginExpired);
|
|
1376
|
+
abort(s.installStopped);
|
|
1223
1377
|
return;
|
|
1224
1378
|
}
|
|
1225
1379
|
if (!clientIds.length) {
|
|
1226
|
-
emit("error",
|
|
1227
|
-
abort(
|
|
1380
|
+
emit("error", s.selectAtLeastOne);
|
|
1381
|
+
abort(s.installStopped);
|
|
1228
1382
|
return;
|
|
1229
1383
|
}
|
|
1230
|
-
emit("info",
|
|
1231
|
-
emit("info",
|
|
1232
|
-
emit("info",
|
|
1384
|
+
emit("info", s.connectedTo(session.accountLabel));
|
|
1385
|
+
emit("info", s.toolFlags(includeWrite, telemetryEnabled));
|
|
1386
|
+
emit("info", s.refreshingDetection);
|
|
1233
1387
|
const detected = await detectClients();
|
|
1234
1388
|
const selected = detected.filter((client) => clientIds.includes(client.id));
|
|
1235
1389
|
const selectedHasOnlyManualSetup = selected.length > 0 && selected.every(isManualSetupClient);
|
|
1236
1390
|
if (!selected.length) {
|
|
1237
|
-
emit("error",
|
|
1238
|
-
abort(
|
|
1391
|
+
emit("error", s.noSelectedDetected);
|
|
1392
|
+
abort(s.installStopped);
|
|
1239
1393
|
return;
|
|
1240
1394
|
}
|
|
1241
1395
|
let okCount = 0;
|
|
1242
1396
|
for (const client of selected) {
|
|
1243
|
-
emit("active", isManualSetupClient(client) ?
|
|
1397
|
+
emit("active", isManualSetupClient(client) ? s.preparingManual(client.label) : s.installing(client.label));
|
|
1244
1398
|
const result = await installInto(client, session, includeWrite, telemetryEnabled);
|
|
1245
1399
|
if (result.ok) {
|
|
1246
1400
|
okCount += 1;
|
|
@@ -1249,8 +1403,8 @@ async function streamInstall(url, res, onDone) {
|
|
|
1249
1403
|
emit("error", `${result.label}: ${result.message}`);
|
|
1250
1404
|
}
|
|
1251
1405
|
}
|
|
1252
|
-
const summary = selectedHasOnlyManualSetup ?
|
|
1253
|
-
const closing = selectedHasOnlyManualSetup ?
|
|
1406
|
+
const summary = selectedHasOnlyManualSetup ? s.manualReady : s.installedSummary(okCount, selected.length);
|
|
1407
|
+
const closing = selectedHasOnlyManualSetup ? s.followManual : s.restartClients;
|
|
1254
1408
|
emit(okCount > 0 ? "success" : "error", summary);
|
|
1255
1409
|
if (okCount > 0) {
|
|
1256
1410
|
finish(closing);
|
|
@@ -1265,6 +1419,8 @@ async function streamUninstall(url, res, onDone) {
|
|
|
1265
1419
|
connection: "keep-alive"
|
|
1266
1420
|
});
|
|
1267
1421
|
const clientIds = (url.searchParams.get("clients") ?? "").split(",").filter(Boolean);
|
|
1422
|
+
const locale = parseLocale(url.searchParams.get("locale"));
|
|
1423
|
+
const s = MESSAGES[locale].server;
|
|
1268
1424
|
const emit = (level, message) => sendSse(res, { level, message });
|
|
1269
1425
|
const abort = (msg) => {
|
|
1270
1426
|
emit("done", msg);
|
|
@@ -1276,20 +1432,20 @@ async function streamUninstall(url, res, onDone) {
|
|
|
1276
1432
|
onDone?.();
|
|
1277
1433
|
};
|
|
1278
1434
|
if (!clientIds.length) {
|
|
1279
|
-
emit("error",
|
|
1280
|
-
abort(
|
|
1435
|
+
emit("error", s.selectAtLeastOne);
|
|
1436
|
+
abort(s.uninstallStopped);
|
|
1281
1437
|
return;
|
|
1282
1438
|
}
|
|
1283
1439
|
const detected = await detectClients();
|
|
1284
1440
|
const selected = detected.filter((c) => clientIds.includes(c.id));
|
|
1285
1441
|
if (!selected.length) {
|
|
1286
|
-
emit("error",
|
|
1287
|
-
abort(
|
|
1442
|
+
emit("error", s.noSelectedDetected);
|
|
1443
|
+
abort(s.uninstallStopped);
|
|
1288
1444
|
return;
|
|
1289
1445
|
}
|
|
1290
1446
|
let okCount = 0;
|
|
1291
1447
|
for (const client of selected) {
|
|
1292
|
-
emit("active",
|
|
1448
|
+
emit("active", s.removing(client.label));
|
|
1293
1449
|
let res2;
|
|
1294
1450
|
if (client.id === "claude-code") {
|
|
1295
1451
|
res2 = await uninstallFromClaudeCode();
|
|
@@ -1307,16 +1463,17 @@ async function streamUninstall(url, res, onDone) {
|
|
|
1307
1463
|
emit("error", `${client.label}: ${res2.message}`);
|
|
1308
1464
|
}
|
|
1309
1465
|
}
|
|
1310
|
-
emit(okCount > 0 ? "success" : "error",
|
|
1311
|
-
finish(
|
|
1466
|
+
emit(okCount > 0 ? "success" : "error", s.removedSummary(okCount, selected.length));
|
|
1467
|
+
finish(s.completeRemoval);
|
|
1312
1468
|
}
|
|
1313
|
-
function pageUninstallHtml() {
|
|
1469
|
+
function pageUninstallHtml(locale = "en") {
|
|
1470
|
+
const ui = MESSAGES[locale].uninstaller;
|
|
1314
1471
|
return `<!doctype html>
|
|
1315
|
-
<html lang="
|
|
1472
|
+
<html lang="${locale}">
|
|
1316
1473
|
<head>
|
|
1317
1474
|
<meta charset="utf-8" />
|
|
1318
1475
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
1319
|
-
<title
|
|
1476
|
+
<title>${ui.docTitle}</title>
|
|
1320
1477
|
<style>
|
|
1321
1478
|
:root { color-scheme: light; --bg:#fff; --card:#fff; --strong:#1d2228; --muted:#9aa0ab; --line:#e7e9ee; --accent:#0d0f0e; --danger:#d14343; --ok:#16a34a; --warn:#b06a00; }
|
|
1322
1479
|
* { box-sizing:border-box; }
|
|
@@ -1368,8 +1525,8 @@ function pageUninstallHtml() {
|
|
|
1368
1525
|
<main>
|
|
1369
1526
|
<div class="steps"><div class="dot active" id="dot-1"></div><div class="dot" id="dot-2"></div></div>
|
|
1370
1527
|
<div class="card">
|
|
1371
|
-
<h1 id="title"
|
|
1372
|
-
<p class="sub" id="sub"
|
|
1528
|
+
<h1 id="title">${ui.steps[1].title}</h1>
|
|
1529
|
+
<p class="sub" id="sub">${ui.steps[1].sub}</p>
|
|
1373
1530
|
|
|
1374
1531
|
<section id="step-1">
|
|
1375
1532
|
<div class="spinner" id="spinner"></div>
|
|
@@ -1387,19 +1544,18 @@ function pageUninstallHtml() {
|
|
|
1387
1544
|
</section>
|
|
1388
1545
|
|
|
1389
1546
|
<div class="actions">
|
|
1390
|
-
<button id="back" class="ghost hidden"
|
|
1391
|
-
<button id="refresh"
|
|
1392
|
-
<button class="danger" id="next"
|
|
1547
|
+
<button id="back" class="ghost hidden">${ui.btnBack}</button>
|
|
1548
|
+
<button id="refresh">${ui.btnRefresh}</button>
|
|
1549
|
+
<button class="danger" id="next">${ui.btnRemove}</button>
|
|
1393
1550
|
</div>
|
|
1394
1551
|
</div>
|
|
1395
1552
|
<p class="version">v${VERSION}</p>
|
|
1396
1553
|
</main>
|
|
1397
1554
|
<script>
|
|
1555
|
+
const LOCALE = "${locale}";
|
|
1556
|
+
const T = ${JSON.stringify(ui)};
|
|
1398
1557
|
const $ = (id) => document.getElementById(id);
|
|
1399
|
-
const STEPS =
|
|
1400
|
-
1: { title: "Remove Leadbay MCP", sub: "Select the agents to remove Leadbay MCP from." },
|
|
1401
|
-
2: { title: "Removing", sub: "Keep this window open until it's done." },
|
|
1402
|
-
};
|
|
1558
|
+
const STEPS = T.steps;
|
|
1403
1559
|
const CHECK = "M20 33 l8 8 l16 -18";
|
|
1404
1560
|
const CROSS = "M22 22 l20 20 M42 22 l-20 20";
|
|
1405
1561
|
let step = 1;
|
|
@@ -1411,18 +1567,18 @@ function pageUninstallHtml() {
|
|
|
1411
1567
|
function showResult(ok, msg) {
|
|
1412
1568
|
$("sub").classList.add("hidden");
|
|
1413
1569
|
$("result-msg").textContent = msg;
|
|
1414
|
-
$("result-note").textContent = ok ?
|
|
1570
|
+
$("result-note").textContent = ok ? T.closeWindow : "";
|
|
1415
1571
|
$("ring-mark").setAttribute("d", ok ? CHECK : CROSS);
|
|
1416
1572
|
const ring = $("ring"); ring.classList.remove("ok", "err"); void ring.getBoundingClientRect();
|
|
1417
1573
|
ring.classList.add(ok ? "ok" : "err");
|
|
1418
1574
|
$("result").classList.toggle("err", !ok);
|
|
1419
1575
|
$("result").classList.remove("hidden");
|
|
1420
|
-
$("title").textContent = ok ?
|
|
1576
|
+
$("title").textContent = ok ? T.allSet : T.somethingWrong;
|
|
1421
1577
|
["next", "back", "refresh"].forEach((id) => $(id).classList.add("hidden"));
|
|
1422
1578
|
}
|
|
1423
|
-
function renderAgents() { $("spinner").classList.add("hidden"); const root = $("agents"); if (!clients.length) { root.innerHTML = '<div class="sub">
|
|
1424
|
-
async function refresh() { $("spinner").classList.remove("hidden"); $("agents").innerHTML = ""; const res = await fetch("/api/status"); const data = await res.json(); clients = (data.clients || []).filter((c) => c.configured); renderAgents(); if (!clients.length) say(
|
|
1425
|
-
async function doUninstall() { const selected = [...document.querySelectorAll("[data-client]:checked")].map((el) => el.dataset.client); if (!selected.length) return say(
|
|
1579
|
+
function renderAgents() { $("spinner").classList.add("hidden"); const root = $("agents"); if (!clients.length) { root.innerHTML = '<div class="sub">' + esc(T.noInstallDetected) + '</div>'; return; } root.innerHTML = clients.map((c) => '<label class="agent"><input type="checkbox" data-client="' + esc(c.id) + '" checked /><span><strong>' + esc(c.label) + '</strong><span class="detail">' + esc(c.detail) + '</span></span></label>').join(""); }
|
|
1580
|
+
async function refresh() { $("spinner").classList.remove("hidden"); $("agents").innerHTML = ""; const res = await fetch("/api/status"); const data = await res.json(); clients = (data.clients || []).filter((c) => c.configured); renderAgents(); if (!clients.length) say(T.noInstallDetected); }
|
|
1581
|
+
async function doUninstall() { const selected = [...document.querySelectorAll("[data-client]:checked")].map((el) => el.dataset.client); if (!selected.length) return say(T.selectAtLeastOne, true); setStep(2); let okCount = 0, lastError = ""; const params = new URLSearchParams({ clients: selected.join(","), locale: LOCALE }); const events = new EventSource("/api/uninstall-stream?" + params.toString()); events.onmessage = (event) => { const data = JSON.parse(event.data); if (data.level === "error") lastError = data.message; if (data.level === "success") okCount += 1; if (data.level === "done") { events.close(); const ok = okCount > 0 && !lastError; showResult(ok, ok ? T.successRemoved : (lastError || T.noneRemoved)); } else { say(data.message, data.level === "error"); } }; events.onerror = () => { events.close(); showResult(false, T.streamDisconnected); }; }
|
|
1426
1582
|
$("back").addEventListener("click", () => setStep(1));
|
|
1427
1583
|
$("refresh").addEventListener("click", refresh);
|
|
1428
1584
|
$("next").addEventListener("click", doUninstall);
|
|
@@ -1431,13 +1587,14 @@ function pageUninstallHtml() {
|
|
|
1431
1587
|
</body>
|
|
1432
1588
|
</html>`;
|
|
1433
1589
|
}
|
|
1434
|
-
function pageHtml() {
|
|
1590
|
+
function pageHtml(locale = "en") {
|
|
1591
|
+
const ui = MESSAGES[locale].installer;
|
|
1435
1592
|
return `<!doctype html>
|
|
1436
|
-
<html lang="
|
|
1593
|
+
<html lang="${locale}">
|
|
1437
1594
|
<head>
|
|
1438
1595
|
<meta charset="utf-8" />
|
|
1439
1596
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
1440
|
-
<title
|
|
1597
|
+
<title>${ui.docTitle}</title>
|
|
1441
1598
|
<style>
|
|
1442
1599
|
:root { color-scheme: light; --bg:#fff; --card:#fff; --strong:#1d2228; --muted:#9aa0ab; --line:#e7e9ee; --accent:#0d0f0e; --cancel-line:#f0c8b8; --danger:#d14343; --ok:#16a34a; --warn:#b06a00; }
|
|
1443
1600
|
* { box-sizing:border-box; }
|
|
@@ -1493,8 +1650,8 @@ function pageHtml() {
|
|
|
1493
1650
|
<main>
|
|
1494
1651
|
<div class="steps"><div class="dot active" id="dot-1"></div><div class="dot" id="dot-2"></div><div class="dot" id="dot-3"></div></div>
|
|
1495
1652
|
<div class="card">
|
|
1496
|
-
<h1 id="title"
|
|
1497
|
-
<p class="sub" id="sub"
|
|
1653
|
+
<h1 id="title">${ui.steps[1].title}</h1>
|
|
1654
|
+
<p class="sub" id="sub">${ui.steps[1].sub}</p>
|
|
1498
1655
|
|
|
1499
1656
|
<section id="step-2" class="hidden">
|
|
1500
1657
|
<div class="spinner" id="spinner"></div>
|
|
@@ -1512,20 +1669,18 @@ function pageHtml() {
|
|
|
1512
1669
|
</section>
|
|
1513
1670
|
|
|
1514
1671
|
<div class="actions">
|
|
1515
|
-
<button id="back" class="cancel hidden"
|
|
1516
|
-
<button id="refresh" class="ghost hidden"
|
|
1517
|
-
<button class="primary" id="next"
|
|
1672
|
+
<button id="back" class="cancel hidden">${ui.btnBack}</button>
|
|
1673
|
+
<button id="refresh" class="ghost hidden">${ui.btnRefresh}</button>
|
|
1674
|
+
<button class="primary" id="next">${ui.btnSignIn}</button>
|
|
1518
1675
|
</div>
|
|
1519
1676
|
</div>
|
|
1520
1677
|
<p class="version">v${VERSION}</p>
|
|
1521
1678
|
</main>
|
|
1522
1679
|
<script>
|
|
1680
|
+
const LOCALE = "${locale}";
|
|
1681
|
+
const T = ${JSON.stringify(ui)};
|
|
1523
1682
|
const $ = (id) => document.getElementById(id);
|
|
1524
|
-
const STEPS =
|
|
1525
|
-
1: { title: "Connect Leadbay", sub: "Sign in to install Leadbay across your AI agents." },
|
|
1526
|
-
2: { title: "Choose your agents", sub: "Pick where to install Leadbay." },
|
|
1527
|
-
3: { title: "Installing", sub: "Keep this window open until it's done." },
|
|
1528
|
-
};
|
|
1683
|
+
const STEPS = T.steps;
|
|
1529
1684
|
const CHECK = "M20 33 l8 8 l16 -18";
|
|
1530
1685
|
const CROSS = "M22 22 l20 20 M42 22 l-20 20";
|
|
1531
1686
|
let step = 1;
|
|
@@ -1543,30 +1698,30 @@ function pageHtml() {
|
|
|
1543
1698
|
$("back").classList.toggle("hidden", step !== 2);
|
|
1544
1699
|
$("refresh").classList.toggle("hidden", step !== 2);
|
|
1545
1700
|
$("next").classList.toggle("hidden", step === 3);
|
|
1546
|
-
$("next").textContent = step === 2 ?
|
|
1701
|
+
$("next").textContent = step === 2 ? T.btnInstall : T.btnSignIn;
|
|
1547
1702
|
}
|
|
1548
1703
|
// Final completion state: animated green check / red cross + message.
|
|
1549
1704
|
function showResult(ok, msg) {
|
|
1550
1705
|
$("sub").classList.add("hidden");
|
|
1551
1706
|
$("result-msg").textContent = msg;
|
|
1552
|
-
$("result-note").textContent = ok ?
|
|
1707
|
+
$("result-note").textContent = ok ? T.closeWindow : "";
|
|
1553
1708
|
$("ring-mark").setAttribute("d", ok ? CHECK : CROSS);
|
|
1554
1709
|
const ring = $("ring"); ring.classList.remove("ok", "err"); void ring.getBoundingClientRect();
|
|
1555
1710
|
ring.classList.add(ok ? "ok" : "err");
|
|
1556
1711
|
$("result").classList.toggle("err", !ok);
|
|
1557
1712
|
$("result").classList.remove("hidden");
|
|
1558
|
-
$("title").textContent = ok ?
|
|
1713
|
+
$("title").textContent = ok ? T.allSet : T.somethingWrong;
|
|
1559
1714
|
["next", "back", "refresh"].forEach((id) => $(id).classList.add("hidden"));
|
|
1560
1715
|
}
|
|
1561
|
-
function renderAgents() { $("spinner").classList.add("hidden"); const root = $("agents"); if (!clients.length) { root.innerHTML = '<div class="sub">
|
|
1562
|
-
async function refresh() { $("spinner").classList.remove("hidden"); $("agents").innerHTML = ""; const res = await fetch("/api/status"); const data = await res.json(); clients = data.clients || []; renderAgents(); if (!clients.length) say(
|
|
1563
|
-
async function doLogin() { $("next").disabled = true; say(
|
|
1716
|
+
function renderAgents() { $("spinner").classList.add("hidden"); const root = $("agents"); if (!clients.length) { root.innerHTML = '<div class="sub">' + esc(T.noClientsDetected) + '</div>'; return; } root.innerHTML = clients.map((client) => { const manual = client.id === "chatgpt-desktop"; const badgeText = manual ? T.badgeManual : client.configured ? T.badgeUpdate : T.badgeInstall; const badgeClass = manual ? "badge-update" : client.configured ? "badge-update" : "badge-install"; return '<label class="agent"><input type="checkbox" data-client="' + esc(client.id) + '" checked /><span><strong>' + esc(client.label) + ' <span class="badge-pill ' + badgeClass + '">' + esc(badgeText) + '</span></strong><span class="detail">' + esc(client.detail) + '</span></span></label>'; }).join(""); }
|
|
1717
|
+
async function refresh() { $("spinner").classList.remove("hidden"); $("agents").innerHTML = ""; const res = await fetch("/api/status"); const data = await res.json(); clients = data.clients || []; renderAgents(); if (!clients.length) say(T.noAgentsDetected); }
|
|
1718
|
+
async function doLogin() { $("next").disabled = true; say(T.openingSignIn); try { const res = await fetch("/api/oauth-login", { method:"POST" }); const data = await res.json(); if (!data.ok) return say(data.error || T.oauthFailed, true); sessionId = data.sessionId; setStep(2); await refresh(); } finally { $("next").disabled = false; } }
|
|
1564
1719
|
async function install() {
|
|
1565
1720
|
const selected = [...document.querySelectorAll("[data-client]:checked")].map((el) => el.dataset.client);
|
|
1566
|
-
if (!selected.length) return say(
|
|
1721
|
+
if (!selected.length) return say(T.selectAtLeastOne, true);
|
|
1567
1722
|
setStep(3);
|
|
1568
1723
|
let okCount = 0, lastError = "";
|
|
1569
|
-
const params = new URLSearchParams({ sessionId, clients: selected.join(","), write: "1", telemetry: "1" });
|
|
1724
|
+
const params = new URLSearchParams({ sessionId, clients: selected.join(","), write: "1", telemetry: "1", locale: LOCALE });
|
|
1570
1725
|
const events = new EventSource("/api/install-stream?" + params.toString());
|
|
1571
1726
|
events.onmessage = (event) => {
|
|
1572
1727
|
const data = JSON.parse(event.data);
|
|
@@ -1575,12 +1730,12 @@ function pageHtml() {
|
|
|
1575
1730
|
if (data.level === "done") {
|
|
1576
1731
|
events.close();
|
|
1577
1732
|
const ok = okCount > 0 && !lastError;
|
|
1578
|
-
showResult(ok, ok ?
|
|
1733
|
+
showResult(ok, ok ? T.successInstalled : (lastError || T.noneInstalled));
|
|
1579
1734
|
} else {
|
|
1580
1735
|
say(data.message, data.level === "error");
|
|
1581
1736
|
}
|
|
1582
1737
|
};
|
|
1583
|
-
events.onerror = () => { events.close(); showResult(false,
|
|
1738
|
+
events.onerror = () => { events.close(); showResult(false, T.streamDisconnected); };
|
|
1584
1739
|
}
|
|
1585
1740
|
$("back").addEventListener("click", () => setStep(1));
|
|
1586
1741
|
$("refresh").addEventListener("click", refresh);
|
|
@@ -1635,7 +1790,7 @@ function makeGuiServer(options, pageContent, extraRoutes, logLabel) {
|
|
|
1635
1790
|
}
|
|
1636
1791
|
try {
|
|
1637
1792
|
if (req.method === "GET" && req.url === "/") {
|
|
1638
|
-
const raw = pageContent();
|
|
1793
|
+
const raw = await pageContent();
|
|
1639
1794
|
res.writeHead(200, { "content-type": "text/html; charset=utf-8", "content-length": Buffer.byteLength(raw) });
|
|
1640
1795
|
res.end(raw);
|
|
1641
1796
|
return;
|
|
@@ -1662,7 +1817,7 @@ function makeGuiServer(options, pageContent, extraRoutes, logLabel) {
|
|
|
1662
1817
|
});
|
|
1663
1818
|
}
|
|
1664
1819
|
function startInstallerGui(options = {}) {
|
|
1665
|
-
return makeGuiServer(options, pageHtml, async (req, res, onDone) => {
|
|
1820
|
+
return makeGuiServer(options, async () => pageHtml(await detectLocale()), async (req, res, onDone) => {
|
|
1666
1821
|
if (req.method === "GET" && req.url === "/api/status") {
|
|
1667
1822
|
sendJson(res, 200, { os: formatInstallOsLabel(), hostedMcpUrl: HOSTED_MCP_URL, clients: await clientsWithConfiguredStatus() });
|
|
1668
1823
|
return true;
|
|
@@ -1683,7 +1838,7 @@ function startInstallerGui(options = {}) {
|
|
|
1683
1838
|
}, "installer");
|
|
1684
1839
|
}
|
|
1685
1840
|
function startUninstallerGui(options = {}) {
|
|
1686
|
-
return makeGuiServer(options, pageUninstallHtml, async (req, res, onDone) => {
|
|
1841
|
+
return makeGuiServer(options, async () => pageUninstallHtml(await detectLocale()), async (req, res, onDone) => {
|
|
1687
1842
|
if (req.method === "GET" && req.url === "/api/status") {
|
|
1688
1843
|
sendJson(res, 200, { os: formatInstallOsLabel(), clients: await clientsWithConfiguredStatus() });
|
|
1689
1844
|
return true;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@leadbay/mcp",
|
|
3
|
-
"version": "0.23.
|
|
3
|
+
"version": "0.23.7",
|
|
4
4
|
"mcpName": "io.github.leadbay/leadbay-mcp",
|
|
5
5
|
"description": "Model Context Protocol (MCP) server for Leadbay — AI lead discovery, qualification, and enrichment for Claude Desktop, Cursor, and Claude Code.",
|
|
6
6
|
"type": "module",
|