@leadbay/mcp 0.39.2 → 0.39.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bin.js +248 -38
- package/dist/http-server.js +240 -38
- package/dist/installer-electron.js +1 -1
- package/dist/installer-gui.js +1 -1
- package/package.json +1 -1
package/dist/bin.js
CHANGED
|
@@ -14249,8 +14249,8 @@ function summarise(responses) {
|
|
|
14249
14249
|
return { answered, total, avg_qualification_boost: avg, best_response_excerpt: excerpt };
|
|
14250
14250
|
}
|
|
14251
14251
|
function buildPullLeadsNextSteps(args) {
|
|
14252
|
-
const { leadCount, hasMore, nextPage, computingWishlist, computingScores } = args;
|
|
14253
|
-
if (
|
|
14252
|
+
const { leadCount: leadCount2, hasMore, nextPage, computingWishlist, computingScores } = args;
|
|
14253
|
+
if (leadCount2 <= 0) {
|
|
14254
14254
|
if (computingWishlist || computingScores) {
|
|
14255
14255
|
return {
|
|
14256
14256
|
question: "This lens is still warming up. What next?",
|
|
@@ -14503,15 +14503,15 @@ var init_pull_leads = __esm({
|
|
|
14503
14503
|
const currentPage = res.pagination?.page ?? page;
|
|
14504
14504
|
const hasMore = currentPage < totalPages - 1;
|
|
14505
14505
|
const nextPage = hasMore ? currentPage + 1 : null;
|
|
14506
|
-
const
|
|
14506
|
+
const leadCount2 = res.items.length;
|
|
14507
14507
|
const nextSteps = buildPullLeadsNextSteps({
|
|
14508
|
-
leadCount,
|
|
14508
|
+
leadCount: leadCount2,
|
|
14509
14509
|
hasMore,
|
|
14510
14510
|
nextPage,
|
|
14511
14511
|
computingWishlist: res.computing_wishlist,
|
|
14512
14512
|
computingScores: res.computing_scores
|
|
14513
14513
|
});
|
|
14514
|
-
const lensIsEmpty =
|
|
14514
|
+
const lensIsEmpty = leadCount2 === 0 && (res.pagination?.total ?? 0) === 0;
|
|
14515
14515
|
const emptyReason = lensIsEmpty ? await diagnoseEmptyLens(client, lensId, {
|
|
14516
14516
|
wishlist: res.computing_wishlist,
|
|
14517
14517
|
scores: res.computing_scores
|
|
@@ -20808,27 +20808,167 @@ var init_bulk_enrich_status = __esm({
|
|
|
20808
20808
|
}
|
|
20809
20809
|
});
|
|
20810
20810
|
|
|
20811
|
-
// ../core/dist/composite/
|
|
20812
|
-
function
|
|
20813
|
-
|
|
20814
|
-
return [];
|
|
20815
|
-
return s.toLowerCase().split(/[^\p{L}\p{N}]+/u).filter(Boolean);
|
|
20811
|
+
// ../core/dist/composite/_sector-resolver.js
|
|
20812
|
+
function normalizeSectorText(value) {
|
|
20813
|
+
return (value ?? "").normalize("NFD").replace(/[\u0300-\u036f]/g, "").toLowerCase().replace(/[^0-9a-z]+/g, " ").trim();
|
|
20816
20814
|
}
|
|
20817
|
-
function
|
|
20818
|
-
|
|
20819
|
-
|
|
20820
|
-
|
|
20821
|
-
|
|
20822
|
-
|
|
20815
|
+
function singular(token) {
|
|
20816
|
+
if (token.length > 4 && token.endsWith("ies"))
|
|
20817
|
+
return `${token.slice(0, -3)}y`;
|
|
20818
|
+
return token.length > 3 && token.endsWith("s") ? token.slice(0, -1) : token;
|
|
20819
|
+
}
|
|
20820
|
+
function sectorTokens(value) {
|
|
20821
|
+
const all = normalizeSectorText(value).split(" ").filter(Boolean).map(singular);
|
|
20822
|
+
const core = all.filter((t) => !FILLER.has(t));
|
|
20823
|
+
return core.length > 0 ? core : all;
|
|
20824
|
+
}
|
|
20825
|
+
function sectorLabel(row) {
|
|
20826
|
+
if (!row)
|
|
20827
|
+
return "";
|
|
20828
|
+
const label = row.label;
|
|
20829
|
+
if (typeof label === "string" && label.length > 0)
|
|
20830
|
+
return label;
|
|
20831
|
+
return typeof row.name === "string" ? row.name : "";
|
|
20832
|
+
}
|
|
20833
|
+
function leadCount(row) {
|
|
20834
|
+
const n = row.number_of_leads;
|
|
20835
|
+
return typeof n === "number" && Number.isFinite(n) ? n : 0;
|
|
20836
|
+
}
|
|
20837
|
+
function rankCandidates(scored, tieBreak) {
|
|
20838
|
+
const out = [];
|
|
20839
|
+
const seen = /* @__PURE__ */ new Set();
|
|
20840
|
+
scored.sort((a, b) => b.score - a.score || (tieBreak === "breadth" ? leadCount(b.row) - leadCount(a.row) || b.closeness - a.closeness : b.closeness - a.closeness || leadCount(b.row) - leadCount(a.row)) || sectorLabel(a.row).length - sectorLabel(b.row).length).forEach(({ row, score }) => {
|
|
20841
|
+
const label = sectorLabel(row);
|
|
20842
|
+
if (!label || seen.has(label) || out.length >= MAX_CANDIDATES)
|
|
20843
|
+
return;
|
|
20844
|
+
seen.add(label);
|
|
20845
|
+
out.push({ id: row.id, name: label, score: Number(score.toFixed(2)) });
|
|
20846
|
+
});
|
|
20847
|
+
return out;
|
|
20848
|
+
}
|
|
20849
|
+
function matchSector(text3, taxonomy) {
|
|
20850
|
+
const wanted = normalizeSectorText(text3);
|
|
20851
|
+
if (!wanted)
|
|
20852
|
+
return { kind: "unresolved", candidates: [] };
|
|
20853
|
+
const exact = taxonomy.filter((row) => normalizeSectorText(sectorLabel(row)) === wanted);
|
|
20854
|
+
if (exact.length > 0) {
|
|
20855
|
+
const label = sectorLabel(exact.reduce((best, row) => leadCount(row) > leadCount(best) ? row : best));
|
|
20856
|
+
const ids = taxonomy.filter((row) => sectorLabel(row) === label).map((row) => row.id);
|
|
20857
|
+
return { kind: "resolved", label, ids, exact: true };
|
|
20858
|
+
}
|
|
20859
|
+
const want = new Set(sectorTokens(text3));
|
|
20860
|
+
const sameWords = taxonomy.filter((row) => {
|
|
20861
|
+
const have = new Set(sectorTokens(sectorLabel(row)));
|
|
20862
|
+
return have.size === want.size && [...want].every((token) => have.has(token));
|
|
20863
|
+
});
|
|
20864
|
+
const sameWordLabels = new Set(sameWords.map((row) => sectorLabel(row)).filter(Boolean));
|
|
20865
|
+
if (sameWordLabels.size === 1) {
|
|
20866
|
+
const label = [...sameWordLabels][0];
|
|
20867
|
+
const ids = taxonomy.filter((row) => sectorLabel(row) === label).map((row) => row.id);
|
|
20868
|
+
return { kind: "resolved", label, ids, exact: false };
|
|
20869
|
+
}
|
|
20870
|
+
const scored = [];
|
|
20871
|
+
for (const row of taxonomy) {
|
|
20872
|
+
const have = new Set(sectorTokens(sectorLabel(row)));
|
|
20873
|
+
if (have.size === 0)
|
|
20874
|
+
continue;
|
|
20823
20875
|
let overlap = 0;
|
|
20824
|
-
for (const
|
|
20825
|
-
if (have.has(
|
|
20876
|
+
for (const token of want)
|
|
20877
|
+
if (have.has(token))
|
|
20826
20878
|
overlap += 1;
|
|
20827
|
-
|
|
20828
|
-
|
|
20829
|
-
|
|
20830
|
-
|
|
20879
|
+
if (overlap === 0)
|
|
20880
|
+
continue;
|
|
20881
|
+
scored.push({ row, score: overlap / want.size, closeness: overlap / have.size });
|
|
20882
|
+
}
|
|
20883
|
+
const full = scored.filter((s) => s.score >= 1);
|
|
20884
|
+
return {
|
|
20885
|
+
kind: "unresolved",
|
|
20886
|
+
candidates: full.length > 0 ? rankCandidates(full, "breadth") : rankCandidates(scored, "closeness").slice(0, MAX_PARTIAL_CANDIDATES)
|
|
20887
|
+
};
|
|
20888
|
+
}
|
|
20889
|
+
function sectorSections(taxonomy) {
|
|
20890
|
+
const roots = taxonomy.filter((row) => !row.parent);
|
|
20891
|
+
const labels = [];
|
|
20892
|
+
for (const row of roots.sort((a, b) => leadCount(b) - leadCount(a))) {
|
|
20893
|
+
const label = sectorLabel(row);
|
|
20894
|
+
if (label && !labels.includes(label))
|
|
20895
|
+
labels.push(label);
|
|
20896
|
+
}
|
|
20897
|
+
return labels;
|
|
20831
20898
|
}
|
|
20899
|
+
async function fetchSectorTaxonomy(client, ctx) {
|
|
20900
|
+
const me = await client.resolveMe().catch(() => null);
|
|
20901
|
+
const lang = me?.language ?? "en";
|
|
20902
|
+
const taxonomy = await client.request("GET", `/sectors/all?lang=${encodeURIComponent(lang)}&includeInvisible=false`);
|
|
20903
|
+
const unlabelled = taxonomy.filter((row) => !sectorLabel(row)).length;
|
|
20904
|
+
if (unlabelled > 0) {
|
|
20905
|
+
ctx?.logger?.warn?.(`sector taxonomy: ${unlabelled}/${taxonomy.length} row(s) carry no label`);
|
|
20906
|
+
}
|
|
20907
|
+
return taxonomy;
|
|
20908
|
+
}
|
|
20909
|
+
function resolveSectorValues(values, taxonomy) {
|
|
20910
|
+
const out = {
|
|
20911
|
+
values: [],
|
|
20912
|
+
rewritten: [],
|
|
20913
|
+
unresolved: [],
|
|
20914
|
+
sections: sectorSections(taxonomy)
|
|
20915
|
+
};
|
|
20916
|
+
for (const raw of values) {
|
|
20917
|
+
const asked = typeof raw === "string" ? raw : String(raw ?? "");
|
|
20918
|
+
if (NUMERIC_ID.test(asked.trim())) {
|
|
20919
|
+
out.values.push(asked.trim());
|
|
20920
|
+
continue;
|
|
20921
|
+
}
|
|
20922
|
+
const match = matchSector(asked, taxonomy);
|
|
20923
|
+
if (match.kind === "resolved") {
|
|
20924
|
+
out.values.push(match.label);
|
|
20925
|
+
if (match.label !== asked)
|
|
20926
|
+
out.rewritten.push({ asked, used: match.label });
|
|
20927
|
+
continue;
|
|
20928
|
+
}
|
|
20929
|
+
out.values.push(asked);
|
|
20930
|
+
out.unresolved.push({ asked, closest: match.candidates });
|
|
20931
|
+
}
|
|
20932
|
+
return out;
|
|
20933
|
+
}
|
|
20934
|
+
var FILLER, MAX_CANDIDATES, MAX_PARTIAL_CANDIDATES, NUMERIC_ID;
|
|
20935
|
+
var init_sector_resolver = __esm({
|
|
20936
|
+
"../core/dist/composite/_sector-resolver.js"() {
|
|
20937
|
+
"use strict";
|
|
20938
|
+
FILLER = /* @__PURE__ */ new Set([
|
|
20939
|
+
// en
|
|
20940
|
+
"and",
|
|
20941
|
+
"of",
|
|
20942
|
+
"the",
|
|
20943
|
+
"for",
|
|
20944
|
+
"or",
|
|
20945
|
+
"activity",
|
|
20946
|
+
// fr
|
|
20947
|
+
"et",
|
|
20948
|
+
"de",
|
|
20949
|
+
"des",
|
|
20950
|
+
"du",
|
|
20951
|
+
"d",
|
|
20952
|
+
"la",
|
|
20953
|
+
"le",
|
|
20954
|
+
"les",
|
|
20955
|
+
"l",
|
|
20956
|
+
"en",
|
|
20957
|
+
"aux",
|
|
20958
|
+
"au",
|
|
20959
|
+
"activite",
|
|
20960
|
+
"pour",
|
|
20961
|
+
"sur",
|
|
20962
|
+
"par",
|
|
20963
|
+
"a"
|
|
20964
|
+
]);
|
|
20965
|
+
MAX_CANDIDATES = 8;
|
|
20966
|
+
MAX_PARTIAL_CANDIDATES = 4;
|
|
20967
|
+
NUMERIC_ID = /^\d+$/;
|
|
20968
|
+
}
|
|
20969
|
+
});
|
|
20970
|
+
|
|
20971
|
+
// ../core/dist/composite/adjust-audience.js
|
|
20832
20972
|
async function resolveSectors(client, texts, ctx) {
|
|
20833
20973
|
const looksLikeId2 = (s) => /^\d+$/.test(s);
|
|
20834
20974
|
const direct = texts.filter(looksLikeId2);
|
|
@@ -20838,18 +20978,18 @@ async function resolveSectors(client, texts, ctx) {
|
|
|
20838
20978
|
const me = await client.resolveMe().catch(() => null);
|
|
20839
20979
|
const lang = me?.language ?? "en";
|
|
20840
20980
|
const taxonomy = await client.request("GET", `/sectors/all?lang=${encodeURIComponent(lang)}&includeInvisible=false`);
|
|
20841
|
-
const nullNames = taxonomy.filter((s) => !s
|
|
20981
|
+
const nullNames = taxonomy.filter((s) => !sectorLabel(s)).length;
|
|
20842
20982
|
if (nullNames > 0) {
|
|
20843
20983
|
ctx?.logger?.warn?.(`adjust_audience: /sectors/all returned ${nullNames}/${taxonomy.length} sector(s) with a null/missing name`);
|
|
20844
20984
|
}
|
|
20845
20985
|
const resolved = [...direct];
|
|
20846
20986
|
const ambiguities = [];
|
|
20847
20987
|
for (const text3 of free) {
|
|
20848
|
-
const
|
|
20849
|
-
if (
|
|
20850
|
-
resolved.push(
|
|
20988
|
+
const match = matchSector(text3, taxonomy);
|
|
20989
|
+
if (match.kind === "resolved") {
|
|
20990
|
+
resolved.push(...match.ids);
|
|
20851
20991
|
} else {
|
|
20852
|
-
ambiguities.push({ sector_text: text3, matches });
|
|
20992
|
+
ambiguities.push({ sector_text: text3, matches: match.candidates });
|
|
20853
20993
|
}
|
|
20854
20994
|
}
|
|
20855
20995
|
return { resolved, ambiguities };
|
|
@@ -20956,6 +21096,7 @@ var init_adjust_audience = __esm({
|
|
|
20956
21096
|
"use strict";
|
|
20957
21097
|
init_geo_helpers();
|
|
20958
21098
|
init_country_guard();
|
|
21099
|
+
init_sector_resolver();
|
|
20959
21100
|
init_tool_descriptions_generated();
|
|
20960
21101
|
adjustAudience = {
|
|
20961
21102
|
name: "leadbay_adjust_audience",
|
|
@@ -22173,12 +22314,68 @@ function sortFilterLists(filters) {
|
|
|
22173
22314
|
}
|
|
22174
22315
|
return out;
|
|
22175
22316
|
}
|
|
22317
|
+
function isSectorRejection(err) {
|
|
22318
|
+
const e = err;
|
|
22319
|
+
return !!e && e.code === "BAD_INPUT" && typeof e.message === "string" && e.message.includes("filters.sectors");
|
|
22320
|
+
}
|
|
22321
|
+
async function submitSearch(client, body, opts, ctx) {
|
|
22322
|
+
try {
|
|
22323
|
+
return {
|
|
22324
|
+
ok: true,
|
|
22325
|
+
data: await client.request("POST", "/mcp/search", body, opts),
|
|
22326
|
+
rewritten: []
|
|
22327
|
+
};
|
|
22328
|
+
} catch (err) {
|
|
22329
|
+
const asked = body.filters?.sectors;
|
|
22330
|
+
if (!isSectorRejection(err) || !Array.isArray(asked) || asked.length === 0) {
|
|
22331
|
+
throw err;
|
|
22332
|
+
}
|
|
22333
|
+
const taxonomy = await fetchSectorTaxonomy(client, ctx).catch(() => {
|
|
22334
|
+
throw err;
|
|
22335
|
+
});
|
|
22336
|
+
const fix = resolveSectorValues(asked, taxonomy);
|
|
22337
|
+
if (fix.unresolved.length === 0 && fix.rewritten.length === 0)
|
|
22338
|
+
throw err;
|
|
22339
|
+
if (fix.unresolved.length > 0)
|
|
22340
|
+
return { ok: false, choice: sectorChoice(fix) };
|
|
22341
|
+
const retried = { ...body, filters: { ...body.filters, sectors: fix.values } };
|
|
22342
|
+
return {
|
|
22343
|
+
ok: true,
|
|
22344
|
+
data: await client.request("POST", "/mcp/search", retried, opts),
|
|
22345
|
+
rewritten: fix.rewritten
|
|
22346
|
+
};
|
|
22347
|
+
}
|
|
22348
|
+
}
|
|
22349
|
+
function sectorNote(rewritten) {
|
|
22350
|
+
if (rewritten.length === 0)
|
|
22351
|
+
return void 0;
|
|
22352
|
+
const pairs = rewritten.map((r) => `"${r.asked}" \u2192 "${r.used}"`).join(", ");
|
|
22353
|
+
return {
|
|
22354
|
+
sectors_note: `Leadbay's sector taxonomy spells these differently, so the search ran on ${pairs}. Tell the user which sector was searched.`,
|
|
22355
|
+
sectors_used: rewritten
|
|
22356
|
+
};
|
|
22357
|
+
}
|
|
22358
|
+
function sectorChoice(fix) {
|
|
22359
|
+
const names = fix.unresolved.map((u) => `"${u.asked}"`).join(", ");
|
|
22360
|
+
return {
|
|
22361
|
+
mode: "needs_sector_choice",
|
|
22362
|
+
submitted: false,
|
|
22363
|
+
unresolved_sectors: fix.unresolved.map((u) => ({
|
|
22364
|
+
asked: u.asked,
|
|
22365
|
+
closest: u.closest.map((c) => c.name)
|
|
22366
|
+
})),
|
|
22367
|
+
sector_sections: fix.sections,
|
|
22368
|
+
resolved_sectors: fix.rewritten,
|
|
22369
|
+
hint: `No sector in this workspace's taxonomy is named ${names || "that"}. Nothing was submitted and nothing was spent. Re-call with a label copied character for character from \`closest\` or \`sector_sections\` (a section covers everything under it), or drop \`filters.sectors\` and put the wording in \`query\` / \`example_lead.description\` instead \u2014 the search then RANKS on it rather than fencing on it, which is usually what the user meant. \`leadbay_list_sectors\` returns the full taxonomy if none of these fit.`
|
|
22370
|
+
};
|
|
22371
|
+
}
|
|
22176
22372
|
var DEFAULT_WAIT_SECONDS, findNewLeads;
|
|
22177
22373
|
var init_find_new_leads = __esm({
|
|
22178
22374
|
"../core/dist/composite/find-new-leads.js"() {
|
|
22179
22375
|
"use strict";
|
|
22180
22376
|
init_mcp_job_helpers();
|
|
22181
22377
|
init_country_guard();
|
|
22378
|
+
init_sector_resolver();
|
|
22182
22379
|
init_tool_descriptions_generated();
|
|
22183
22380
|
DEFAULT_WAIT_SECONDS = 45;
|
|
22184
22381
|
findNewLeads = {
|
|
@@ -22219,7 +22416,7 @@ var init_find_new_leads = __esm({
|
|
|
22219
22416
|
},
|
|
22220
22417
|
filters: {
|
|
22221
22418
|
type: "object",
|
|
22222
|
-
description: "HARD constraints (the seed only shapes ranking). Sector/location labels resolve at submit;
|
|
22419
|
+
description: "HARD constraints (the seed only shapes ranking). Sector/location labels resolve at submit. `sectors` must be a label from Leadbay's own taxonomy (leadbay_list_sectors) \u2014 everyday wording like 'Professional Services' is not one; a spelling/plural slip is corrected for you, but a word with no label comes back as mode:'needs_sector_choice' with the labels to pick from. An unresolvable location is a 400 naming it.",
|
|
22223
22420
|
properties: {
|
|
22224
22421
|
sectors: { type: "array", items: { type: "string" } },
|
|
22225
22422
|
locations: { type: "array", items: { type: "string" } },
|
|
@@ -22391,19 +22588,27 @@ var init_find_new_leads = __esm({
|
|
|
22391
22588
|
dry_run: dryRun
|
|
22392
22589
|
});
|
|
22393
22590
|
if (dryRun === true) {
|
|
22394
|
-
const
|
|
22591
|
+
const attempt2 = await submitSearch(client, body, void 0, ctx);
|
|
22592
|
+
if (!attempt2.ok)
|
|
22593
|
+
return { ...attempt2.choice, ...countryNote, region: client.region };
|
|
22395
22594
|
return {
|
|
22396
22595
|
dry_run: true,
|
|
22397
|
-
...
|
|
22596
|
+
...attempt2.data,
|
|
22597
|
+
...sectorNote(attempt2.rewritten),
|
|
22398
22598
|
...countryNote,
|
|
22399
22599
|
region: client.region
|
|
22400
22600
|
};
|
|
22401
22601
|
}
|
|
22402
22602
|
if (isPaid && !consented) {
|
|
22403
|
-
|
|
22404
|
-
|
|
22405
|
-
|
|
22406
|
-
|
|
22603
|
+
let forecast = null;
|
|
22604
|
+
let quoteRewritten = [];
|
|
22605
|
+
if (!vetoed) {
|
|
22606
|
+
const attempt2 = await submitSearch(client, { ...body, dry_run: true }, void 0, ctx);
|
|
22607
|
+
if (!attempt2.ok)
|
|
22608
|
+
return { ...attempt2.choice, ...countryNote, region: client.region };
|
|
22609
|
+
forecast = attempt2.data;
|
|
22610
|
+
quoteRewritten = attempt2.rewritten;
|
|
22611
|
+
}
|
|
22407
22612
|
return {
|
|
22408
22613
|
mode: "needs_confirmation",
|
|
22409
22614
|
submitted: false,
|
|
@@ -22416,11 +22621,15 @@ var init_find_new_leads = __esm({
|
|
|
22416
22621
|
estimated_cost: forecast?.estimated_cost ?? null,
|
|
22417
22622
|
items_requested: forecast?.items_requested ?? null,
|
|
22418
22623
|
hint: vetoed ? "confirm:false vetoed the run \u2014 nothing was submitted. Re-call with confirm:true to proceed, or drop qualify/channels for a free search." : "Tell the user what will run and that it uses their plan's quota (no amounts, no money), get an explicit go-ahead, then re-call with confirm:true. For a free search instead: omit qualify and channels.",
|
|
22624
|
+
...sectorNote(quoteRewritten),
|
|
22419
22625
|
...countryNote,
|
|
22420
22626
|
region: client.region
|
|
22421
22627
|
};
|
|
22422
22628
|
}
|
|
22423
|
-
const
|
|
22629
|
+
const attempt = await submitSearch(client, body, { preSendSignal: ctx?.signal }, ctx);
|
|
22630
|
+
if (!attempt.ok)
|
|
22631
|
+
return { ...attempt.choice, ...countryNote, region: client.region };
|
|
22632
|
+
const submit = attempt.data;
|
|
22424
22633
|
const mocked = mockedSubmitPreview(submit, "leadbay_find_new_leads", client.region);
|
|
22425
22634
|
if (mocked)
|
|
22426
22635
|
return mocked;
|
|
@@ -22471,6 +22680,7 @@ var init_find_new_leads = __esm({
|
|
|
22471
22680
|
since: snapshot.next_since ?? null,
|
|
22472
22681
|
suggested_wait_seconds: done ? 0 : 60
|
|
22473
22682
|
},
|
|
22683
|
+
...sectorNote(attempt.rewritten),
|
|
22474
22684
|
...countryNote,
|
|
22475
22685
|
region: client.region
|
|
22476
22686
|
};
|
|
@@ -24019,8 +24229,8 @@ var init_report_outreach = __esm({
|
|
|
24019
24229
|
if (!params.dry_run && params.verification.source === "user_confirmed" && typeof ctx?.elicit === "function") {
|
|
24020
24230
|
try {
|
|
24021
24231
|
const targetIds = params.lead_ids ?? [params.lead_id];
|
|
24022
|
-
const
|
|
24023
|
-
const elicitMsg =
|
|
24232
|
+
const leadCount2 = targetIds.length;
|
|
24233
|
+
const elicitMsg = leadCount2 === 1 ? `An AI agent wants to log outreach on lead ${targetIds[0]}: "${params.note}". The agent claims you confirmed this. Type your literal confirmation to proceed; cancel to reject.` : `An AI agent wants to log outreach on ${leadCount2} leads: "${params.note}". The agent claims you confirmed this. Type your literal confirmation to proceed; cancel to reject.`;
|
|
24024
24234
|
const result = await ctx.elicit({
|
|
24025
24235
|
message: elicitMsg,
|
|
24026
24236
|
requestedSchema: {
|
|
@@ -31378,7 +31588,7 @@ var OAUTH_BASE_URLS = {
|
|
|
31378
31588
|
fr: "https://staging.api.leadbay.app"
|
|
31379
31589
|
}
|
|
31380
31590
|
};
|
|
31381
|
-
var VERSION = "0.39.
|
|
31591
|
+
var VERSION = "0.39.3";
|
|
31382
31592
|
var HELP = `
|
|
31383
31593
|
leadbay-mcp ${VERSION} \u2014 Leadbay Model Context Protocol server
|
|
31384
31594
|
|
package/dist/http-server.js
CHANGED
|
@@ -16691,8 +16691,8 @@ function summarise(responses) {
|
|
|
16691
16691
|
return { answered, total, avg_qualification_boost: avg, best_response_excerpt: excerpt };
|
|
16692
16692
|
}
|
|
16693
16693
|
function buildPullLeadsNextSteps(args) {
|
|
16694
|
-
const { leadCount, hasMore, nextPage, computingWishlist, computingScores } = args;
|
|
16695
|
-
if (
|
|
16694
|
+
const { leadCount: leadCount2, hasMore, nextPage, computingWishlist, computingScores } = args;
|
|
16695
|
+
if (leadCount2 <= 0) {
|
|
16696
16696
|
if (computingWishlist || computingScores) {
|
|
16697
16697
|
return {
|
|
16698
16698
|
question: "This lens is still warming up. What next?",
|
|
@@ -16937,15 +16937,15 @@ var pullLeads = {
|
|
|
16937
16937
|
const currentPage = res.pagination?.page ?? page;
|
|
16938
16938
|
const hasMore = currentPage < totalPages - 1;
|
|
16939
16939
|
const nextPage = hasMore ? currentPage + 1 : null;
|
|
16940
|
-
const
|
|
16940
|
+
const leadCount2 = res.items.length;
|
|
16941
16941
|
const nextSteps = buildPullLeadsNextSteps({
|
|
16942
|
-
leadCount,
|
|
16942
|
+
leadCount: leadCount2,
|
|
16943
16943
|
hasMore,
|
|
16944
16944
|
nextPage,
|
|
16945
16945
|
computingWishlist: res.computing_wishlist,
|
|
16946
16946
|
computingScores: res.computing_scores
|
|
16947
16947
|
});
|
|
16948
|
-
const lensIsEmpty =
|
|
16948
|
+
const lensIsEmpty = leadCount2 === 0 && (res.pagination?.total ?? 0) === 0;
|
|
16949
16949
|
const emptyReason = lensIsEmpty ? await diagnoseEmptyLens(client, lensId, {
|
|
16950
16950
|
wishlist: res.computing_wishlist,
|
|
16951
16951
|
scores: res.computing_scores
|
|
@@ -22998,27 +22998,161 @@ var bulkEnrichStatus = {
|
|
|
22998
22998
|
}
|
|
22999
22999
|
};
|
|
23000
23000
|
|
|
23001
|
-
// ../core/dist/composite/
|
|
23002
|
-
|
|
23003
|
-
|
|
23004
|
-
|
|
23005
|
-
|
|
23001
|
+
// ../core/dist/composite/_sector-resolver.js
|
|
23002
|
+
var FILLER = /* @__PURE__ */ new Set([
|
|
23003
|
+
// en
|
|
23004
|
+
"and",
|
|
23005
|
+
"of",
|
|
23006
|
+
"the",
|
|
23007
|
+
"for",
|
|
23008
|
+
"or",
|
|
23009
|
+
"activity",
|
|
23010
|
+
// fr
|
|
23011
|
+
"et",
|
|
23012
|
+
"de",
|
|
23013
|
+
"des",
|
|
23014
|
+
"du",
|
|
23015
|
+
"d",
|
|
23016
|
+
"la",
|
|
23017
|
+
"le",
|
|
23018
|
+
"les",
|
|
23019
|
+
"l",
|
|
23020
|
+
"en",
|
|
23021
|
+
"aux",
|
|
23022
|
+
"au",
|
|
23023
|
+
"activite",
|
|
23024
|
+
"pour",
|
|
23025
|
+
"sur",
|
|
23026
|
+
"par",
|
|
23027
|
+
"a"
|
|
23028
|
+
]);
|
|
23029
|
+
function normalizeSectorText(value) {
|
|
23030
|
+
return (value ?? "").normalize("NFD").replace(/[\u0300-\u036f]/g, "").toLowerCase().replace(/[^0-9a-z]+/g, " ").trim();
|
|
23006
23031
|
}
|
|
23007
|
-
function
|
|
23008
|
-
|
|
23009
|
-
|
|
23010
|
-
|
|
23011
|
-
|
|
23012
|
-
|
|
23032
|
+
function singular(token) {
|
|
23033
|
+
if (token.length > 4 && token.endsWith("ies"))
|
|
23034
|
+
return `${token.slice(0, -3)}y`;
|
|
23035
|
+
return token.length > 3 && token.endsWith("s") ? token.slice(0, -1) : token;
|
|
23036
|
+
}
|
|
23037
|
+
function sectorTokens(value) {
|
|
23038
|
+
const all = normalizeSectorText(value).split(" ").filter(Boolean).map(singular);
|
|
23039
|
+
const core = all.filter((t) => !FILLER.has(t));
|
|
23040
|
+
return core.length > 0 ? core : all;
|
|
23041
|
+
}
|
|
23042
|
+
function sectorLabel(row) {
|
|
23043
|
+
if (!row)
|
|
23044
|
+
return "";
|
|
23045
|
+
const label = row.label;
|
|
23046
|
+
if (typeof label === "string" && label.length > 0)
|
|
23047
|
+
return label;
|
|
23048
|
+
return typeof row.name === "string" ? row.name : "";
|
|
23049
|
+
}
|
|
23050
|
+
function leadCount(row) {
|
|
23051
|
+
const n = row.number_of_leads;
|
|
23052
|
+
return typeof n === "number" && Number.isFinite(n) ? n : 0;
|
|
23053
|
+
}
|
|
23054
|
+
var MAX_CANDIDATES = 8;
|
|
23055
|
+
var MAX_PARTIAL_CANDIDATES = 4;
|
|
23056
|
+
function rankCandidates(scored, tieBreak) {
|
|
23057
|
+
const out = [];
|
|
23058
|
+
const seen = /* @__PURE__ */ new Set();
|
|
23059
|
+
scored.sort((a, b) => b.score - a.score || (tieBreak === "breadth" ? leadCount(b.row) - leadCount(a.row) || b.closeness - a.closeness : b.closeness - a.closeness || leadCount(b.row) - leadCount(a.row)) || sectorLabel(a.row).length - sectorLabel(b.row).length).forEach(({ row, score }) => {
|
|
23060
|
+
const label = sectorLabel(row);
|
|
23061
|
+
if (!label || seen.has(label) || out.length >= MAX_CANDIDATES)
|
|
23062
|
+
return;
|
|
23063
|
+
seen.add(label);
|
|
23064
|
+
out.push({ id: row.id, name: label, score: Number(score.toFixed(2)) });
|
|
23065
|
+
});
|
|
23066
|
+
return out;
|
|
23067
|
+
}
|
|
23068
|
+
function matchSector(text3, taxonomy) {
|
|
23069
|
+
const wanted = normalizeSectorText(text3);
|
|
23070
|
+
if (!wanted)
|
|
23071
|
+
return { kind: "unresolved", candidates: [] };
|
|
23072
|
+
const exact = taxonomy.filter((row) => normalizeSectorText(sectorLabel(row)) === wanted);
|
|
23073
|
+
if (exact.length > 0) {
|
|
23074
|
+
const label = sectorLabel(exact.reduce((best, row) => leadCount(row) > leadCount(best) ? row : best));
|
|
23075
|
+
const ids = taxonomy.filter((row) => sectorLabel(row) === label).map((row) => row.id);
|
|
23076
|
+
return { kind: "resolved", label, ids, exact: true };
|
|
23077
|
+
}
|
|
23078
|
+
const want = new Set(sectorTokens(text3));
|
|
23079
|
+
const sameWords = taxonomy.filter((row) => {
|
|
23080
|
+
const have = new Set(sectorTokens(sectorLabel(row)));
|
|
23081
|
+
return have.size === want.size && [...want].every((token) => have.has(token));
|
|
23082
|
+
});
|
|
23083
|
+
const sameWordLabels = new Set(sameWords.map((row) => sectorLabel(row)).filter(Boolean));
|
|
23084
|
+
if (sameWordLabels.size === 1) {
|
|
23085
|
+
const label = [...sameWordLabels][0];
|
|
23086
|
+
const ids = taxonomy.filter((row) => sectorLabel(row) === label).map((row) => row.id);
|
|
23087
|
+
return { kind: "resolved", label, ids, exact: false };
|
|
23088
|
+
}
|
|
23089
|
+
const scored = [];
|
|
23090
|
+
for (const row of taxonomy) {
|
|
23091
|
+
const have = new Set(sectorTokens(sectorLabel(row)));
|
|
23092
|
+
if (have.size === 0)
|
|
23093
|
+
continue;
|
|
23013
23094
|
let overlap = 0;
|
|
23014
|
-
for (const
|
|
23015
|
-
if (have.has(
|
|
23095
|
+
for (const token of want)
|
|
23096
|
+
if (have.has(token))
|
|
23016
23097
|
overlap += 1;
|
|
23017
|
-
|
|
23018
|
-
|
|
23019
|
-
|
|
23020
|
-
|
|
23098
|
+
if (overlap === 0)
|
|
23099
|
+
continue;
|
|
23100
|
+
scored.push({ row, score: overlap / want.size, closeness: overlap / have.size });
|
|
23101
|
+
}
|
|
23102
|
+
const full = scored.filter((s) => s.score >= 1);
|
|
23103
|
+
return {
|
|
23104
|
+
kind: "unresolved",
|
|
23105
|
+
candidates: full.length > 0 ? rankCandidates(full, "breadth") : rankCandidates(scored, "closeness").slice(0, MAX_PARTIAL_CANDIDATES)
|
|
23106
|
+
};
|
|
23107
|
+
}
|
|
23108
|
+
function sectorSections(taxonomy) {
|
|
23109
|
+
const roots = taxonomy.filter((row) => !row.parent);
|
|
23110
|
+
const labels = [];
|
|
23111
|
+
for (const row of roots.sort((a, b) => leadCount(b) - leadCount(a))) {
|
|
23112
|
+
const label = sectorLabel(row);
|
|
23113
|
+
if (label && !labels.includes(label))
|
|
23114
|
+
labels.push(label);
|
|
23115
|
+
}
|
|
23116
|
+
return labels;
|
|
23021
23117
|
}
|
|
23118
|
+
async function fetchSectorTaxonomy(client, ctx) {
|
|
23119
|
+
const me = await client.resolveMe().catch(() => null);
|
|
23120
|
+
const lang = me?.language ?? "en";
|
|
23121
|
+
const taxonomy = await client.request("GET", `/sectors/all?lang=${encodeURIComponent(lang)}&includeInvisible=false`);
|
|
23122
|
+
const unlabelled = taxonomy.filter((row) => !sectorLabel(row)).length;
|
|
23123
|
+
if (unlabelled > 0) {
|
|
23124
|
+
ctx?.logger?.warn?.(`sector taxonomy: ${unlabelled}/${taxonomy.length} row(s) carry no label`);
|
|
23125
|
+
}
|
|
23126
|
+
return taxonomy;
|
|
23127
|
+
}
|
|
23128
|
+
var NUMERIC_ID = /^\d+$/;
|
|
23129
|
+
function resolveSectorValues(values, taxonomy) {
|
|
23130
|
+
const out = {
|
|
23131
|
+
values: [],
|
|
23132
|
+
rewritten: [],
|
|
23133
|
+
unresolved: [],
|
|
23134
|
+
sections: sectorSections(taxonomy)
|
|
23135
|
+
};
|
|
23136
|
+
for (const raw of values) {
|
|
23137
|
+
const asked = typeof raw === "string" ? raw : String(raw ?? "");
|
|
23138
|
+
if (NUMERIC_ID.test(asked.trim())) {
|
|
23139
|
+
out.values.push(asked.trim());
|
|
23140
|
+
continue;
|
|
23141
|
+
}
|
|
23142
|
+
const match = matchSector(asked, taxonomy);
|
|
23143
|
+
if (match.kind === "resolved") {
|
|
23144
|
+
out.values.push(match.label);
|
|
23145
|
+
if (match.label !== asked)
|
|
23146
|
+
out.rewritten.push({ asked, used: match.label });
|
|
23147
|
+
continue;
|
|
23148
|
+
}
|
|
23149
|
+
out.values.push(asked);
|
|
23150
|
+
out.unresolved.push({ asked, closest: match.candidates });
|
|
23151
|
+
}
|
|
23152
|
+
return out;
|
|
23153
|
+
}
|
|
23154
|
+
|
|
23155
|
+
// ../core/dist/composite/adjust-audience.js
|
|
23022
23156
|
async function resolveSectors(client, texts, ctx) {
|
|
23023
23157
|
const looksLikeId2 = (s) => /^\d+$/.test(s);
|
|
23024
23158
|
const direct = texts.filter(looksLikeId2);
|
|
@@ -23028,18 +23162,18 @@ async function resolveSectors(client, texts, ctx) {
|
|
|
23028
23162
|
const me = await client.resolveMe().catch(() => null);
|
|
23029
23163
|
const lang = me?.language ?? "en";
|
|
23030
23164
|
const taxonomy = await client.request("GET", `/sectors/all?lang=${encodeURIComponent(lang)}&includeInvisible=false`);
|
|
23031
|
-
const nullNames = taxonomy.filter((s) => !s
|
|
23165
|
+
const nullNames = taxonomy.filter((s) => !sectorLabel(s)).length;
|
|
23032
23166
|
if (nullNames > 0) {
|
|
23033
23167
|
ctx?.logger?.warn?.(`adjust_audience: /sectors/all returned ${nullNames}/${taxonomy.length} sector(s) with a null/missing name`);
|
|
23034
23168
|
}
|
|
23035
23169
|
const resolved = [...direct];
|
|
23036
23170
|
const ambiguities = [];
|
|
23037
23171
|
for (const text3 of free) {
|
|
23038
|
-
const
|
|
23039
|
-
if (
|
|
23040
|
-
resolved.push(
|
|
23172
|
+
const match = matchSector(text3, taxonomy);
|
|
23173
|
+
if (match.kind === "resolved") {
|
|
23174
|
+
resolved.push(...match.ids);
|
|
23041
23175
|
} else {
|
|
23042
|
-
ambiguities.push({ sector_text: text3, matches });
|
|
23176
|
+
ambiguities.push({ sector_text: text3, matches: match.candidates });
|
|
23043
23177
|
}
|
|
23044
23178
|
}
|
|
23045
23179
|
return { resolved, ambiguities };
|
|
@@ -24334,6 +24468,61 @@ function sortFilterLists(filters) {
|
|
|
24334
24468
|
}
|
|
24335
24469
|
return out;
|
|
24336
24470
|
}
|
|
24471
|
+
function isSectorRejection(err) {
|
|
24472
|
+
const e = err;
|
|
24473
|
+
return !!e && e.code === "BAD_INPUT" && typeof e.message === "string" && e.message.includes("filters.sectors");
|
|
24474
|
+
}
|
|
24475
|
+
async function submitSearch(client, body, opts, ctx) {
|
|
24476
|
+
try {
|
|
24477
|
+
return {
|
|
24478
|
+
ok: true,
|
|
24479
|
+
data: await client.request("POST", "/mcp/search", body, opts),
|
|
24480
|
+
rewritten: []
|
|
24481
|
+
};
|
|
24482
|
+
} catch (err) {
|
|
24483
|
+
const asked = body.filters?.sectors;
|
|
24484
|
+
if (!isSectorRejection(err) || !Array.isArray(asked) || asked.length === 0) {
|
|
24485
|
+
throw err;
|
|
24486
|
+
}
|
|
24487
|
+
const taxonomy = await fetchSectorTaxonomy(client, ctx).catch(() => {
|
|
24488
|
+
throw err;
|
|
24489
|
+
});
|
|
24490
|
+
const fix = resolveSectorValues(asked, taxonomy);
|
|
24491
|
+
if (fix.unresolved.length === 0 && fix.rewritten.length === 0)
|
|
24492
|
+
throw err;
|
|
24493
|
+
if (fix.unresolved.length > 0)
|
|
24494
|
+
return { ok: false, choice: sectorChoice(fix) };
|
|
24495
|
+
const retried = { ...body, filters: { ...body.filters, sectors: fix.values } };
|
|
24496
|
+
return {
|
|
24497
|
+
ok: true,
|
|
24498
|
+
data: await client.request("POST", "/mcp/search", retried, opts),
|
|
24499
|
+
rewritten: fix.rewritten
|
|
24500
|
+
};
|
|
24501
|
+
}
|
|
24502
|
+
}
|
|
24503
|
+
function sectorNote(rewritten) {
|
|
24504
|
+
if (rewritten.length === 0)
|
|
24505
|
+
return void 0;
|
|
24506
|
+
const pairs = rewritten.map((r) => `"${r.asked}" \u2192 "${r.used}"`).join(", ");
|
|
24507
|
+
return {
|
|
24508
|
+
sectors_note: `Leadbay's sector taxonomy spells these differently, so the search ran on ${pairs}. Tell the user which sector was searched.`,
|
|
24509
|
+
sectors_used: rewritten
|
|
24510
|
+
};
|
|
24511
|
+
}
|
|
24512
|
+
function sectorChoice(fix) {
|
|
24513
|
+
const names = fix.unresolved.map((u) => `"${u.asked}"`).join(", ");
|
|
24514
|
+
return {
|
|
24515
|
+
mode: "needs_sector_choice",
|
|
24516
|
+
submitted: false,
|
|
24517
|
+
unresolved_sectors: fix.unresolved.map((u) => ({
|
|
24518
|
+
asked: u.asked,
|
|
24519
|
+
closest: u.closest.map((c) => c.name)
|
|
24520
|
+
})),
|
|
24521
|
+
sector_sections: fix.sections,
|
|
24522
|
+
resolved_sectors: fix.rewritten,
|
|
24523
|
+
hint: `No sector in this workspace's taxonomy is named ${names || "that"}. Nothing was submitted and nothing was spent. Re-call with a label copied character for character from \`closest\` or \`sector_sections\` (a section covers everything under it), or drop \`filters.sectors\` and put the wording in \`query\` / \`example_lead.description\` instead \u2014 the search then RANKS on it rather than fencing on it, which is usually what the user meant. \`leadbay_list_sectors\` returns the full taxonomy if none of these fit.`
|
|
24524
|
+
};
|
|
24525
|
+
}
|
|
24337
24526
|
var findNewLeads = {
|
|
24338
24527
|
name: "leadbay_find_new_leads",
|
|
24339
24528
|
annotations: {
|
|
@@ -24372,7 +24561,7 @@ var findNewLeads = {
|
|
|
24372
24561
|
},
|
|
24373
24562
|
filters: {
|
|
24374
24563
|
type: "object",
|
|
24375
|
-
description: "HARD constraints (the seed only shapes ranking). Sector/location labels resolve at submit;
|
|
24564
|
+
description: "HARD constraints (the seed only shapes ranking). Sector/location labels resolve at submit. `sectors` must be a label from Leadbay's own taxonomy (leadbay_list_sectors) \u2014 everyday wording like 'Professional Services' is not one; a spelling/plural slip is corrected for you, but a word with no label comes back as mode:'needs_sector_choice' with the labels to pick from. An unresolvable location is a 400 naming it.",
|
|
24376
24565
|
properties: {
|
|
24377
24566
|
sectors: { type: "array", items: { type: "string" } },
|
|
24378
24567
|
locations: { type: "array", items: { type: "string" } },
|
|
@@ -24544,19 +24733,27 @@ var findNewLeads = {
|
|
|
24544
24733
|
dry_run: dryRun
|
|
24545
24734
|
});
|
|
24546
24735
|
if (dryRun === true) {
|
|
24547
|
-
const
|
|
24736
|
+
const attempt2 = await submitSearch(client, body, void 0, ctx);
|
|
24737
|
+
if (!attempt2.ok)
|
|
24738
|
+
return { ...attempt2.choice, ...countryNote, region: client.region };
|
|
24548
24739
|
return {
|
|
24549
24740
|
dry_run: true,
|
|
24550
|
-
...
|
|
24741
|
+
...attempt2.data,
|
|
24742
|
+
...sectorNote(attempt2.rewritten),
|
|
24551
24743
|
...countryNote,
|
|
24552
24744
|
region: client.region
|
|
24553
24745
|
};
|
|
24554
24746
|
}
|
|
24555
24747
|
if (isPaid && !consented) {
|
|
24556
|
-
|
|
24557
|
-
|
|
24558
|
-
|
|
24559
|
-
|
|
24748
|
+
let forecast = null;
|
|
24749
|
+
let quoteRewritten = [];
|
|
24750
|
+
if (!vetoed) {
|
|
24751
|
+
const attempt2 = await submitSearch(client, { ...body, dry_run: true }, void 0, ctx);
|
|
24752
|
+
if (!attempt2.ok)
|
|
24753
|
+
return { ...attempt2.choice, ...countryNote, region: client.region };
|
|
24754
|
+
forecast = attempt2.data;
|
|
24755
|
+
quoteRewritten = attempt2.rewritten;
|
|
24756
|
+
}
|
|
24560
24757
|
return {
|
|
24561
24758
|
mode: "needs_confirmation",
|
|
24562
24759
|
submitted: false,
|
|
@@ -24569,11 +24766,15 @@ var findNewLeads = {
|
|
|
24569
24766
|
estimated_cost: forecast?.estimated_cost ?? null,
|
|
24570
24767
|
items_requested: forecast?.items_requested ?? null,
|
|
24571
24768
|
hint: vetoed ? "confirm:false vetoed the run \u2014 nothing was submitted. Re-call with confirm:true to proceed, or drop qualify/channels for a free search." : "Tell the user what will run and that it uses their plan's quota (no amounts, no money), get an explicit go-ahead, then re-call with confirm:true. For a free search instead: omit qualify and channels.",
|
|
24769
|
+
...sectorNote(quoteRewritten),
|
|
24572
24770
|
...countryNote,
|
|
24573
24771
|
region: client.region
|
|
24574
24772
|
};
|
|
24575
24773
|
}
|
|
24576
|
-
const
|
|
24774
|
+
const attempt = await submitSearch(client, body, { preSendSignal: ctx?.signal }, ctx);
|
|
24775
|
+
if (!attempt.ok)
|
|
24776
|
+
return { ...attempt.choice, ...countryNote, region: client.region };
|
|
24777
|
+
const submit = attempt.data;
|
|
24577
24778
|
const mocked = mockedSubmitPreview(submit, "leadbay_find_new_leads", client.region);
|
|
24578
24779
|
if (mocked)
|
|
24579
24780
|
return mocked;
|
|
@@ -24624,6 +24825,7 @@ var findNewLeads = {
|
|
|
24624
24825
|
since: snapshot.next_since ?? null,
|
|
24625
24826
|
suggested_wait_seconds: done ? 0 : 60
|
|
24626
24827
|
},
|
|
24828
|
+
...sectorNote(attempt.rewritten),
|
|
24627
24829
|
...countryNote,
|
|
24628
24830
|
region: client.region
|
|
24629
24831
|
};
|
|
@@ -26105,8 +26307,8 @@ var reportOutreach = {
|
|
|
26105
26307
|
if (!params.dry_run && params.verification.source === "user_confirmed" && typeof ctx?.elicit === "function") {
|
|
26106
26308
|
try {
|
|
26107
26309
|
const targetIds = params.lead_ids ?? [params.lead_id];
|
|
26108
|
-
const
|
|
26109
|
-
const elicitMsg =
|
|
26310
|
+
const leadCount2 = targetIds.length;
|
|
26311
|
+
const elicitMsg = leadCount2 === 1 ? `An AI agent wants to log outreach on lead ${targetIds[0]}: "${params.note}". The agent claims you confirmed this. Type your literal confirmation to proceed; cancel to reject.` : `An AI agent wants to log outreach on ${leadCount2} leads: "${params.note}". The agent claims you confirmed this. Type your literal confirmation to proceed; cancel to reject.`;
|
|
26110
26312
|
const result = await ctx.elicit({
|
|
26111
26313
|
message: elicitMsg,
|
|
26112
26314
|
requestedSchema: {
|
|
@@ -28660,7 +28862,7 @@ function parseWriteEnv(env = process.env) {
|
|
|
28660
28862
|
}
|
|
28661
28863
|
|
|
28662
28864
|
// src/http-server.ts
|
|
28663
|
-
var VERSION = true ? "0.39.
|
|
28865
|
+
var VERSION = true ? "0.39.3" : "0.0.0-dev";
|
|
28664
28866
|
var PORT = Number(process.env.PORT ?? 8080);
|
|
28665
28867
|
var HOST = process.env.HOST ?? "0.0.0.0";
|
|
28666
28868
|
var logger = {
|
package/dist/installer-gui.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@leadbay/mcp",
|
|
3
|
-
"version": "0.39.
|
|
3
|
+
"version": "0.39.3",
|
|
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",
|