@leadbay/mcp 0.23.5 → 0.23.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.
@@ -1074,6 +1074,16 @@ import { randomUUID } from "crypto";
1074
1074
  import { resolve as resolvePath } from "path";
1075
1075
  import { fileURLToPath } from "url";
1076
1076
  import { existsSync as existsSync3, readFileSync as readFileSync2 } from "fs";
1077
+ async function detectLocale() {
1078
+ try {
1079
+ return await inferRegionViaStargate({ staging: false }) === "fr" ? "fr" : "en";
1080
+ } catch {
1081
+ return "en";
1082
+ }
1083
+ }
1084
+ function parseLocale(raw) {
1085
+ return raw === "fr" ? "fr" : "en";
1086
+ }
1077
1087
  async function isLeadbayConfigured(client) {
1078
1088
  if (client.id === "claude-code") {
1079
1089
  return await isLeadbayConfiguredInClaudeCode();
@@ -1204,23 +1214,25 @@ async function install(body) {
1204
1214
  cleanupSessions();
1205
1215
  const session = body.sessionId ? sessions.get(body.sessionId) : void 0;
1206
1216
  const clientIds = body.clientIds ?? [];
1207
- if (!session) return { ok: false, output: "Login expired. Go back and sign in again." };
1208
- if (!clientIds.length) return { ok: false, output: "Select at least one agent." };
1217
+ if (!session) return { ok: false, output: MESSAGES.en.server.loginExpired };
1218
+ if (!clientIds.length) return { ok: false, output: MESSAGES.en.server.selectAtLeastOne };
1219
+ const locale = session.region === "fr" ? "fr" : "en";
1220
+ const s = MESSAGES[locale].server;
1209
1221
  const detected = await detectClients();
1210
1222
  const selected = detected.filter((client) => clientIds.includes(client.id));
1211
- if (!selected.length) return { ok: false, output: "No selected agents were detected on this machine." };
1223
+ if (!selected.length) return { ok: false, output: s.noSelectedDetected };
1212
1224
  const includeWrite = body.includeWrite !== false;
1213
1225
  const telemetryEnabled = body.telemetryEnabled !== false;
1214
1226
  const results = [];
1215
1227
  for (const client of selected) results.push(await installInto(client, session, includeWrite, telemetryEnabled));
1216
1228
  const output = [
1217
- `Logged in to ${session.region.toUpperCase()} backend.`,
1218
- `Settings: write tools ${includeWrite ? "on" : "off"}, telemetry ${telemetryEnabled ? "on" : "off"}.`,
1229
+ s.loggedInBackend(session.region),
1230
+ s.settingsLine(includeWrite, telemetryEnabled),
1219
1231
  "",
1220
- "Install summary:",
1232
+ s.installSummaryHeader,
1221
1233
  ...results.map((result) => `${result.ok ? "OK" : "ERROR"} ${result.label}: ${result.message}`),
1222
1234
  "",
1223
- "Restart your MCP client(s) to pick up the new server."
1235
+ s.restartClients
1224
1236
  ].join("\n");
1225
1237
  return { ok: results.some((result) => result.ok), output: sanitizeOutput(output), results };
1226
1238
  }
@@ -1235,6 +1247,8 @@ async function streamInstall(url, res, onDone) {
1235
1247
  const clientIds = (url.searchParams.get("clients") ?? "").split(",").filter(Boolean);
1236
1248
  const includeWrite = url.searchParams.get("write") !== "0";
1237
1249
  const telemetryEnabled = url.searchParams.get("telemetry") !== "0";
1250
+ const locale = parseLocale(url.searchParams.get("locale"));
1251
+ const s = MESSAGES[locale].server;
1238
1252
  const emit = (level, message) => sendSse(res, { level, message: sanitizeOutput(message) });
1239
1253
  const abort = (msg) => {
1240
1254
  emit("done", msg);
@@ -1246,29 +1260,29 @@ async function streamInstall(url, res, onDone) {
1246
1260
  onDone?.();
1247
1261
  };
1248
1262
  if (!session) {
1249
- emit("error", "Login expired. Go back and sign in again.");
1250
- abort("Install stopped.");
1263
+ emit("error", s.loginExpired);
1264
+ abort(s.installStopped);
1251
1265
  return;
1252
1266
  }
1253
1267
  if (!clientIds.length) {
1254
- emit("error", "Select at least one agent.");
1255
- abort("Install stopped.");
1268
+ emit("error", s.selectAtLeastOne);
1269
+ abort(s.installStopped);
1256
1270
  return;
1257
1271
  }
1258
- emit("info", `Connected to ${session.accountLabel}.`);
1259
- emit("info", `Write tools ${includeWrite ? "enabled" : "disabled"}; telemetry ${telemetryEnabled ? "enabled" : "disabled"}.`);
1260
- emit("info", "Refreshing installed-agent detection...");
1272
+ emit("info", s.connectedTo(session.accountLabel));
1273
+ emit("info", s.toolFlags(includeWrite, telemetryEnabled));
1274
+ emit("info", s.refreshingDetection);
1261
1275
  const detected = await detectClients();
1262
1276
  const selected = detected.filter((client) => clientIds.includes(client.id));
1263
1277
  const selectedHasOnlyManualSetup = selected.length > 0 && selected.every(isManualSetupClient);
1264
1278
  if (!selected.length) {
1265
- emit("error", "No selected agents were detected on this machine.");
1266
- abort("Install stopped.");
1279
+ emit("error", s.noSelectedDetected);
1280
+ abort(s.installStopped);
1267
1281
  return;
1268
1282
  }
1269
1283
  let okCount = 0;
1270
1284
  for (const client of selected) {
1271
- emit("active", isManualSetupClient(client) ? `Preparing ${client.label} manual setup...` : `Installing ${client.label}...`);
1285
+ emit("active", isManualSetupClient(client) ? s.preparingManual(client.label) : s.installing(client.label));
1272
1286
  const result = await installInto(client, session, includeWrite, telemetryEnabled);
1273
1287
  if (result.ok) {
1274
1288
  okCount += 1;
@@ -1277,8 +1291,8 @@ async function streamInstall(url, res, onDone) {
1277
1291
  emit("error", `${result.label}: ${result.message}`);
1278
1292
  }
1279
1293
  }
1280
- const summary = selectedHasOnlyManualSetup ? "Manual ChatGPT setup instructions ready." : `${okCount}/${selected.length} agent(s) installed, updated, or prepared.`;
1281
- const closing = selectedHasOnlyManualSetup ? "Follow the manual setup instructions shown above." : "Restart your MCP client(s) to pick up the new server.";
1294
+ const summary = selectedHasOnlyManualSetup ? s.manualReady : s.installedSummary(okCount, selected.length);
1295
+ const closing = selectedHasOnlyManualSetup ? s.followManual : s.restartClients;
1282
1296
  emit(okCount > 0 ? "success" : "error", summary);
1283
1297
  if (okCount > 0) {
1284
1298
  finish(closing);
@@ -1293,6 +1307,8 @@ async function streamUninstall(url, res, onDone) {
1293
1307
  connection: "keep-alive"
1294
1308
  });
1295
1309
  const clientIds = (url.searchParams.get("clients") ?? "").split(",").filter(Boolean);
1310
+ const locale = parseLocale(url.searchParams.get("locale"));
1311
+ const s = MESSAGES[locale].server;
1296
1312
  const emit = (level, message) => sendSse(res, { level, message });
1297
1313
  const abort = (msg) => {
1298
1314
  emit("done", msg);
@@ -1304,20 +1320,20 @@ async function streamUninstall(url, res, onDone) {
1304
1320
  onDone?.();
1305
1321
  };
1306
1322
  if (!clientIds.length) {
1307
- emit("error", "Select at least one agent.");
1308
- abort("Uninstall stopped.");
1323
+ emit("error", s.selectAtLeastOne);
1324
+ abort(s.uninstallStopped);
1309
1325
  return;
1310
1326
  }
1311
1327
  const detected = await detectClients();
1312
1328
  const selected = detected.filter((c) => clientIds.includes(c.id));
1313
1329
  if (!selected.length) {
1314
- emit("error", "No selected agents were detected on this machine.");
1315
- abort("Uninstall stopped.");
1330
+ emit("error", s.noSelectedDetected);
1331
+ abort(s.uninstallStopped);
1316
1332
  return;
1317
1333
  }
1318
1334
  let okCount = 0;
1319
1335
  for (const client of selected) {
1320
- emit("active", `Removing from ${client.label}...`);
1336
+ emit("active", s.removing(client.label));
1321
1337
  let res2;
1322
1338
  if (client.id === "claude-code") {
1323
1339
  res2 = await uninstallFromClaudeCode();
@@ -1335,16 +1351,17 @@ async function streamUninstall(url, res, onDone) {
1335
1351
  emit("error", `${client.label}: ${res2.message}`);
1336
1352
  }
1337
1353
  }
1338
- emit(okCount > 0 ? "success" : "error", `${okCount}/${selected.length} agent(s) removed.`);
1339
- finish("Restart your MCP client(s) to complete the removal.");
1354
+ emit(okCount > 0 ? "success" : "error", s.removedSummary(okCount, selected.length));
1355
+ finish(s.completeRemoval);
1340
1356
  }
1341
- function pageUninstallHtml() {
1357
+ function pageUninstallHtml(locale = "en") {
1358
+ const ui = MESSAGES[locale].uninstaller;
1342
1359
  return `<!doctype html>
1343
- <html lang="en">
1360
+ <html lang="${locale}">
1344
1361
  <head>
1345
1362
  <meta charset="utf-8" />
1346
1363
  <meta name="viewport" content="width=device-width, initial-scale=1" />
1347
- <title>Leadbay MCP uninstaller</title>
1364
+ <title>${ui.docTitle}</title>
1348
1365
  <style>
1349
1366
  :root { color-scheme: light; --bg:#fff; --card:#fff; --strong:#1d2228; --muted:#9aa0ab; --line:#e7e9ee; --accent:#0d0f0e; --danger:#d14343; --ok:#16a34a; --warn:#b06a00; }
1350
1367
  * { box-sizing:border-box; }
@@ -1396,8 +1413,8 @@ function pageUninstallHtml() {
1396
1413
  <main>
1397
1414
  <div class="steps"><div class="dot active" id="dot-1"></div><div class="dot" id="dot-2"></div></div>
1398
1415
  <div class="card">
1399
- <h1 id="title">Remove Leadbay MCP</h1>
1400
- <p class="sub" id="sub">Select the agents to remove Leadbay MCP from.</p>
1416
+ <h1 id="title">${ui.steps[1].title}</h1>
1417
+ <p class="sub" id="sub">${ui.steps[1].sub}</p>
1401
1418
 
1402
1419
  <section id="step-1">
1403
1420
  <div class="spinner" id="spinner"></div>
@@ -1415,19 +1432,18 @@ function pageUninstallHtml() {
1415
1432
  </section>
1416
1433
 
1417
1434
  <div class="actions">
1418
- <button id="back" class="ghost hidden">Back</button>
1419
- <button id="refresh">Refresh</button>
1420
- <button class="danger" id="next">Remove selected</button>
1435
+ <button id="back" class="ghost hidden">${ui.btnBack}</button>
1436
+ <button id="refresh">${ui.btnRefresh}</button>
1437
+ <button class="danger" id="next">${ui.btnRemove}</button>
1421
1438
  </div>
1422
1439
  </div>
1423
1440
  <p class="version">v${VERSION}</p>
1424
1441
  </main>
1425
1442
  <script>
1443
+ const LOCALE = "${locale}";
1444
+ const T = ${JSON.stringify(ui)};
1426
1445
  const $ = (id) => document.getElementById(id);
1427
- const STEPS = {
1428
- 1: { title: "Remove Leadbay MCP", sub: "Select the agents to remove Leadbay MCP from." },
1429
- 2: { title: "Removing", sub: "Keep this window open until it's done." },
1430
- };
1446
+ const STEPS = T.steps;
1431
1447
  const CHECK = "M20 33 l8 8 l16 -18";
1432
1448
  const CROSS = "M22 22 l20 20 M42 22 l-20 20";
1433
1449
  let step = 1;
@@ -1439,18 +1455,18 @@ function pageUninstallHtml() {
1439
1455
  function showResult(ok, msg) {
1440
1456
  $("sub").classList.add("hidden");
1441
1457
  $("result-msg").textContent = msg;
1442
- $("result-note").textContent = ok ? "You can close this window." : "";
1458
+ $("result-note").textContent = ok ? T.closeWindow : "";
1443
1459
  $("ring-mark").setAttribute("d", ok ? CHECK : CROSS);
1444
1460
  const ring = $("ring"); ring.classList.remove("ok", "err"); void ring.getBoundingClientRect();
1445
1461
  ring.classList.add(ok ? "ok" : "err");
1446
1462
  $("result").classList.toggle("err", !ok);
1447
1463
  $("result").classList.remove("hidden");
1448
- $("title").textContent = ok ? "All set" : "Something went wrong";
1464
+ $("title").textContent = ok ? T.allSet : T.somethingWrong;
1449
1465
  ["next", "back", "refresh"].forEach((id) => $(id).classList.add("hidden"));
1450
1466
  }
1451
- function renderAgents() { $("spinner").classList.add("hidden"); const root = $("agents"); if (!clients.length) { root.innerHTML = '<div class="sub">No Leadbay MCP installation detected on this machine.</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(""); }
1452
- 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("No Leadbay MCP installation detected on this machine."); }
1453
- async function doUninstall() { const selected = [...document.querySelectorAll("[data-client]:checked")].map((el) => el.dataset.client); if (!selected.length) return say("Select at least one agent.", true); setStep(2); let okCount = 0, lastError = ""; const params = new URLSearchParams({ clients: selected.join(",") }); 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 ? "MCP successfully removed" : (lastError || "No agents were removed.")); } else { say(data.message, data.level === "error"); } }; events.onerror = () => { events.close(); showResult(false, "Uninstall stream disconnected."); }; }
1467
+ 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(""); }
1468
+ 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); }
1469
+ 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); }; }
1454
1470
  $("back").addEventListener("click", () => setStep(1));
1455
1471
  $("refresh").addEventListener("click", refresh);
1456
1472
  $("next").addEventListener("click", doUninstall);
@@ -1459,13 +1475,14 @@ function pageUninstallHtml() {
1459
1475
  </body>
1460
1476
  </html>`;
1461
1477
  }
1462
- function pageHtml() {
1478
+ function pageHtml(locale = "en") {
1479
+ const ui = MESSAGES[locale].installer;
1463
1480
  return `<!doctype html>
1464
- <html lang="en">
1481
+ <html lang="${locale}">
1465
1482
  <head>
1466
1483
  <meta charset="utf-8" />
1467
1484
  <meta name="viewport" content="width=device-width, initial-scale=1" />
1468
- <title>Leadbay MCP installer</title>
1485
+ <title>${ui.docTitle}</title>
1469
1486
  <style>
1470
1487
  :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; }
1471
1488
  * { box-sizing:border-box; }
@@ -1521,8 +1538,8 @@ function pageHtml() {
1521
1538
  <main>
1522
1539
  <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>
1523
1540
  <div class="card">
1524
- <h1 id="title">Connect Leadbay</h1>
1525
- <p class="sub" id="sub">Sign in to install Leadbay across your AI agents.</p>
1541
+ <h1 id="title">${ui.steps[1].title}</h1>
1542
+ <p class="sub" id="sub">${ui.steps[1].sub}</p>
1526
1543
 
1527
1544
  <section id="step-2" class="hidden">
1528
1545
  <div class="spinner" id="spinner"></div>
@@ -1540,20 +1557,18 @@ function pageHtml() {
1540
1557
  </section>
1541
1558
 
1542
1559
  <div class="actions">
1543
- <button id="back" class="cancel hidden">Back</button>
1544
- <button id="refresh" class="ghost hidden">Refresh</button>
1545
- <button class="primary" id="next">Sign in with Leadbay</button>
1560
+ <button id="back" class="cancel hidden">${ui.btnBack}</button>
1561
+ <button id="refresh" class="ghost hidden">${ui.btnRefresh}</button>
1562
+ <button class="primary" id="next">${ui.btnSignIn}</button>
1546
1563
  </div>
1547
1564
  </div>
1548
1565
  <p class="version">v${VERSION}</p>
1549
1566
  </main>
1550
1567
  <script>
1568
+ const LOCALE = "${locale}";
1569
+ const T = ${JSON.stringify(ui)};
1551
1570
  const $ = (id) => document.getElementById(id);
1552
- const STEPS = {
1553
- 1: { title: "Connect Leadbay", sub: "Sign in to install Leadbay across your AI agents." },
1554
- 2: { title: "Choose your agents", sub: "Pick where to install Leadbay." },
1555
- 3: { title: "Installing", sub: "Keep this window open until it's done." },
1556
- };
1571
+ const STEPS = T.steps;
1557
1572
  const CHECK = "M20 33 l8 8 l16 -18";
1558
1573
  const CROSS = "M22 22 l20 20 M42 22 l-20 20";
1559
1574
  let step = 1;
@@ -1571,30 +1586,30 @@ function pageHtml() {
1571
1586
  $("back").classList.toggle("hidden", step !== 2);
1572
1587
  $("refresh").classList.toggle("hidden", step !== 2);
1573
1588
  $("next").classList.toggle("hidden", step === 3);
1574
- $("next").textContent = step === 2 ? "Install" : "Sign in with Leadbay";
1589
+ $("next").textContent = step === 2 ? T.btnInstall : T.btnSignIn;
1575
1590
  }
1576
1591
  // Final completion state: animated green check / red cross + message.
1577
1592
  function showResult(ok, msg) {
1578
1593
  $("sub").classList.add("hidden");
1579
1594
  $("result-msg").textContent = msg;
1580
- $("result-note").textContent = ok ? "You can close this window." : "";
1595
+ $("result-note").textContent = ok ? T.closeWindow : "";
1581
1596
  $("ring-mark").setAttribute("d", ok ? CHECK : CROSS);
1582
1597
  const ring = $("ring"); ring.classList.remove("ok", "err"); void ring.getBoundingClientRect();
1583
1598
  ring.classList.add(ok ? "ok" : "err");
1584
1599
  $("result").classList.toggle("err", !ok);
1585
1600
  $("result").classList.remove("hidden");
1586
- $("title").textContent = ok ? "All set" : "Something went wrong";
1601
+ $("title").textContent = ok ? T.allSet : T.somethingWrong;
1587
1602
  ["next", "back", "refresh"].forEach((id) => $(id).classList.add("hidden"));
1588
1603
  }
1589
- function renderAgents() { $("spinner").classList.add("hidden"); const root = $("agents"); if (!clients.length) { root.innerHTML = '<div class="sub">No supported MCP client detected on this machine.</div>'; return; } root.innerHTML = clients.map((client) => { const manual = client.id === "chatgpt-desktop"; const badgeText = manual ? "manual" : client.configured ? "update" : "install"; 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 + '">' + badgeText + '</span></strong><span class="detail">' + esc(client.detail) + '</span></span></label>'; }).join(""); }
1590
- 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("No supported agents detected."); }
1591
- async function doLogin() { $("next").disabled = true; say("Opening Leadbay sign-in in your browser..."); try { const res = await fetch("/api/oauth-login", { method:"POST" }); const data = await res.json(); if (!data.ok) return say(data.error || "OAuth login failed.", true); sessionId = data.sessionId; setStep(2); await refresh(); } finally { $("next").disabled = false; } }
1604
+ 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(""); }
1605
+ 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); }
1606
+ 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; } }
1592
1607
  async function install() {
1593
1608
  const selected = [...document.querySelectorAll("[data-client]:checked")].map((el) => el.dataset.client);
1594
- if (!selected.length) return say("Select at least one agent.", true);
1609
+ if (!selected.length) return say(T.selectAtLeastOne, true);
1595
1610
  setStep(3);
1596
1611
  let okCount = 0, lastError = "";
1597
- const params = new URLSearchParams({ sessionId, clients: selected.join(","), write: "1", telemetry: "1" });
1612
+ const params = new URLSearchParams({ sessionId, clients: selected.join(","), write: "1", telemetry: "1", locale: LOCALE });
1598
1613
  const events = new EventSource("/api/install-stream?" + params.toString());
1599
1614
  events.onmessage = (event) => {
1600
1615
  const data = JSON.parse(event.data);
@@ -1603,12 +1618,12 @@ function pageHtml() {
1603
1618
  if (data.level === "done") {
1604
1619
  events.close();
1605
1620
  const ok = okCount > 0 && !lastError;
1606
- showResult(ok, ok ? "MCP successfully installed" : (lastError || "No agents were installed."));
1621
+ showResult(ok, ok ? T.successInstalled : (lastError || T.noneInstalled));
1607
1622
  } else {
1608
1623
  say(data.message, data.level === "error");
1609
1624
  }
1610
1625
  };
1611
- events.onerror = () => { events.close(); showResult(false, "Install stream disconnected."); };
1626
+ events.onerror = () => { events.close(); showResult(false, T.streamDisconnected); };
1612
1627
  }
1613
1628
  $("back").addEventListener("click", () => setStep(1));
1614
1629
  $("refresh").addEventListener("click", refresh);
@@ -1663,7 +1678,7 @@ function makeGuiServer(options, pageContent, extraRoutes, logLabel) {
1663
1678
  }
1664
1679
  try {
1665
1680
  if (req.method === "GET" && req.url === "/") {
1666
- const raw = pageContent();
1681
+ const raw = await pageContent();
1667
1682
  res.writeHead(200, { "content-type": "text/html; charset=utf-8", "content-length": Buffer.byteLength(raw) });
1668
1683
  res.end(raw);
1669
1684
  return;
@@ -1690,7 +1705,7 @@ function makeGuiServer(options, pageContent, extraRoutes, logLabel) {
1690
1705
  });
1691
1706
  }
1692
1707
  function startInstallerGui(options = {}) {
1693
- return makeGuiServer(options, pageHtml, async (req, res, onDone) => {
1708
+ return makeGuiServer(options, async () => pageHtml(await detectLocale()), async (req, res, onDone) => {
1694
1709
  if (req.method === "GET" && req.url === "/api/status") {
1695
1710
  sendJson(res, 200, { os: formatInstallOsLabel(), hostedMcpUrl: HOSTED_MCP_URL, clients: await clientsWithConfiguredStatus() });
1696
1711
  return true;
@@ -1711,7 +1726,7 @@ function startInstallerGui(options = {}) {
1711
1726
  }, "installer");
1712
1727
  }
1713
1728
  function startUninstallerGui(options = {}) {
1714
- return makeGuiServer(options, pageUninstallHtml, async (req, res, onDone) => {
1729
+ return makeGuiServer(options, async () => pageUninstallHtml(await detectLocale()), async (req, res, onDone) => {
1715
1730
  if (req.method === "GET" && req.url === "/api/status") {
1716
1731
  sendJson(res, 200, { os: formatInstallOsLabel(), clients: await clientsWithConfiguredStatus() });
1717
1732
  return true;
@@ -1723,7 +1738,7 @@ function startUninstallerGui(options = {}) {
1723
1738
  return false;
1724
1739
  }, "uninstaller");
1725
1740
  }
1726
- var VERSION, PORT, sessions, OAUTH_BASE_URLS, LOCAL_BIN_PATH;
1741
+ var VERSION, MESSAGES, PORT, sessions, OAUTH_BASE_URLS, LOCAL_BIN_PATH;
1727
1742
  var init_installer_gui = __esm({
1728
1743
  "installer/installer-gui.ts"() {
1729
1744
  "use strict";
@@ -1733,7 +1748,147 @@ var init_installer_gui = __esm({
1733
1748
  init_install_dxt();
1734
1749
  init_install_shared();
1735
1750
  init_oauth();
1736
- VERSION = true ? "0.23.5" : "0.0.0-dev";
1751
+ VERSION = true ? "0.23.6" : "0.0.0-dev";
1752
+ MESSAGES = {
1753
+ en: {
1754
+ installer: {
1755
+ docTitle: "Leadbay MCP installer",
1756
+ steps: {
1757
+ 1: { title: "Connect Leadbay", sub: "Sign in to install Leadbay across your AI agents." },
1758
+ 2: { title: "Choose your agents", sub: "Pick where to install Leadbay." },
1759
+ 3: { title: "Installing", sub: "Keep this window open until it's done." }
1760
+ },
1761
+ btnSignIn: "Sign in with Leadbay",
1762
+ btnInstall: "Install",
1763
+ btnBack: "Back",
1764
+ btnRefresh: "Refresh",
1765
+ noClientsDetected: "No supported MCP client detected on this machine.",
1766
+ noAgentsDetected: "No supported agents detected.",
1767
+ selectAtLeastOne: "Select at least one agent.",
1768
+ openingSignIn: "Opening Leadbay sign-in in your browser...",
1769
+ oauthFailed: "OAuth login failed.",
1770
+ successInstalled: "MCP successfully installed",
1771
+ noneInstalled: "No agents were installed.",
1772
+ streamDisconnected: "Install stream disconnected.",
1773
+ closeWindow: "You can close this window.",
1774
+ allSet: "All set",
1775
+ somethingWrong: "Something went wrong",
1776
+ badgeManual: "manual",
1777
+ badgeUpdate: "update",
1778
+ badgeInstall: "install"
1779
+ },
1780
+ uninstaller: {
1781
+ docTitle: "Leadbay MCP uninstaller",
1782
+ steps: {
1783
+ 1: { title: "Remove Leadbay MCP", sub: "Select the agents to remove Leadbay MCP from." },
1784
+ 2: { title: "Removing", sub: "Keep this window open until it's done." }
1785
+ },
1786
+ btnRemove: "Remove selected",
1787
+ btnBack: "Back",
1788
+ btnRefresh: "Refresh",
1789
+ noInstallDetected: "No Leadbay MCP installation detected on this machine.",
1790
+ selectAtLeastOne: "Select at least one agent.",
1791
+ successRemoved: "MCP successfully removed",
1792
+ noneRemoved: "No agents were removed.",
1793
+ streamDisconnected: "Uninstall stream disconnected.",
1794
+ closeWindow: "You can close this window.",
1795
+ allSet: "All set",
1796
+ somethingWrong: "Something went wrong"
1797
+ },
1798
+ server: {
1799
+ loginExpired: "Login expired. Go back and sign in again.",
1800
+ selectAtLeastOne: "Select at least one agent.",
1801
+ noSelectedDetected: "No selected agents were detected on this machine.",
1802
+ installStopped: "Install stopped.",
1803
+ uninstallStopped: "Uninstall stopped.",
1804
+ connectedTo: (label) => `Connected to ${label}.`,
1805
+ toolFlags: (write, telemetry) => `Write tools ${write ? "enabled" : "disabled"}; telemetry ${telemetry ? "enabled" : "disabled"}.`,
1806
+ refreshingDetection: "Refreshing installed-agent detection...",
1807
+ installing: (label) => `Installing ${label}...`,
1808
+ preparingManual: (label) => `Preparing ${label} manual setup...`,
1809
+ removing: (label) => `Removing from ${label}...`,
1810
+ installedSummary: (ok, total) => `${ok}/${total} agent(s) installed, updated, or prepared.`,
1811
+ manualReady: "Manual ChatGPT setup instructions ready.",
1812
+ removedSummary: (ok, total) => `${ok}/${total} agent(s) removed.`,
1813
+ restartClients: "Restart your MCP client(s) to pick up the new server.",
1814
+ followManual: "Follow the manual setup instructions shown above.",
1815
+ completeRemoval: "Restart your MCP client(s) to complete the removal.",
1816
+ loggedInBackend: (region) => `Logged in to ${region.toUpperCase()} backend.`,
1817
+ settingsLine: (write, telemetry) => `Settings: write tools ${write ? "on" : "off"}, telemetry ${telemetry ? "on" : "off"}.`,
1818
+ installSummaryHeader: "Install summary:",
1819
+ noAgentsRemoved: "No agents were removed."
1820
+ }
1821
+ },
1822
+ fr: {
1823
+ installer: {
1824
+ docTitle: "Installateur Leadbay MCP",
1825
+ steps: {
1826
+ 1: { title: "Connectez Leadbay", sub: "Connectez-vous pour installer Leadbay sur vos agents IA." },
1827
+ 2: { title: "Choisissez vos agents", sub: "Choisissez o\xF9 installer Leadbay." },
1828
+ 3: { title: "Installation en cours", sub: "Gardez cette fen\xEAtre ouverte jusqu'\xE0 la fin." }
1829
+ },
1830
+ btnSignIn: "Se connecter avec Leadbay",
1831
+ btnInstall: "Installer",
1832
+ btnBack: "Retour",
1833
+ btnRefresh: "Actualiser",
1834
+ noClientsDetected: "Aucun client MCP compatible d\xE9tect\xE9 sur cette machine.",
1835
+ noAgentsDetected: "Aucun agent compatible d\xE9tect\xE9.",
1836
+ selectAtLeastOne: "S\xE9lectionnez au moins un agent.",
1837
+ openingSignIn: "Ouverture de la connexion Leadbay dans votre navigateur...",
1838
+ oauthFailed: "\xC9chec de la connexion OAuth.",
1839
+ successInstalled: "MCP install\xE9 avec succ\xE8s",
1840
+ noneInstalled: "Aucun agent n'a \xE9t\xE9 install\xE9.",
1841
+ streamDisconnected: "Flux d'installation interrompu.",
1842
+ closeWindow: "Vous pouvez fermer cette fen\xEAtre.",
1843
+ allSet: "Termin\xE9",
1844
+ somethingWrong: "Une erreur est survenue",
1845
+ badgeManual: "manuel",
1846
+ badgeUpdate: "mettre \xE0 jour",
1847
+ badgeInstall: "installer"
1848
+ },
1849
+ uninstaller: {
1850
+ docTitle: "D\xE9sinstallateur Leadbay MCP",
1851
+ steps: {
1852
+ 1: { title: "Supprimer Leadbay MCP", sub: "S\xE9lectionnez les agents desquels supprimer Leadbay MCP." },
1853
+ 2: { title: "Suppression en cours", sub: "Gardez cette fen\xEAtre ouverte jusqu'\xE0 la fin." }
1854
+ },
1855
+ btnRemove: "Supprimer la s\xE9lection",
1856
+ btnBack: "Retour",
1857
+ btnRefresh: "Actualiser",
1858
+ noInstallDetected: "Aucune installation Leadbay MCP d\xE9tect\xE9e sur cette machine.",
1859
+ selectAtLeastOne: "S\xE9lectionnez au moins un agent.",
1860
+ successRemoved: "MCP supprim\xE9 avec succ\xE8s",
1861
+ noneRemoved: "Aucun agent n'a \xE9t\xE9 supprim\xE9.",
1862
+ streamDisconnected: "Flux de d\xE9sinstallation interrompu.",
1863
+ closeWindow: "Vous pouvez fermer cette fen\xEAtre.",
1864
+ allSet: "Termin\xE9",
1865
+ somethingWrong: "Une erreur est survenue"
1866
+ },
1867
+ server: {
1868
+ loginExpired: "Session expir\xE9e. Revenez en arri\xE8re et reconnectez-vous.",
1869
+ selectAtLeastOne: "S\xE9lectionnez au moins un agent.",
1870
+ noSelectedDetected: "Aucun des agents s\xE9lectionn\xE9s n'a \xE9t\xE9 d\xE9tect\xE9 sur cette machine.",
1871
+ installStopped: "Installation arr\xEAt\xE9e.",
1872
+ uninstallStopped: "D\xE9sinstallation arr\xEAt\xE9e.",
1873
+ connectedTo: (label) => `Connect\xE9 \xE0 ${label}.`,
1874
+ toolFlags: (write, telemetry) => `Outils d'\xE9criture ${write ? "activ\xE9s" : "d\xE9sactiv\xE9s"} ; t\xE9l\xE9m\xE9trie ${telemetry ? "activ\xE9e" : "d\xE9sactiv\xE9e"}.`,
1875
+ refreshingDetection: "Actualisation de la d\xE9tection des agents install\xE9s...",
1876
+ installing: (label) => `Installation de ${label}...`,
1877
+ preparingManual: (label) => `Pr\xE9paration de la configuration manuelle de ${label}...`,
1878
+ removing: (label) => `Suppression de ${label}...`,
1879
+ installedSummary: (ok, total) => `${ok}/${total} agent(s) install\xE9(s), mis \xE0 jour ou pr\xE9par\xE9(s).`,
1880
+ manualReady: "Instructions de configuration manuelle de ChatGPT pr\xEAtes.",
1881
+ removedSummary: (ok, total) => `${ok}/${total} agent(s) supprim\xE9(s).`,
1882
+ restartClients: "Red\xE9marrez votre/vos client(s) MCP pour charger le nouveau serveur.",
1883
+ followManual: "Suivez les instructions de configuration manuelle ci-dessus.",
1884
+ completeRemoval: "Red\xE9marrez votre/vos client(s) MCP pour terminer la suppression.",
1885
+ loggedInBackend: (region) => `Connect\xE9 au backend ${region.toUpperCase()}.`,
1886
+ settingsLine: (write, telemetry) => `Param\xE8tres : outils d'\xE9criture ${write ? "activ\xE9s" : "d\xE9sactiv\xE9s"}, t\xE9l\xE9m\xE9trie ${telemetry ? "activ\xE9e" : "d\xE9sactiv\xE9e"}.`,
1887
+ installSummaryHeader: "R\xE9capitulatif de l'installation :",
1888
+ noAgentsRemoved: "Aucun agent n'a \xE9t\xE9 supprim\xE9."
1889
+ }
1890
+ }
1891
+ };
1737
1892
  PORT = Number(process.env.LEADBAY_INSTALLER_PORT ?? 0);
1738
1893
  sessions = /* @__PURE__ */ new Map();
1739
1894
  OAUTH_BASE_URLS = {