@leadbay/mcp 0.23.4 → 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.
- package/CHANGELOG.md +6 -0
- package/dist/bin.js +177 -25
- package/dist/http-server.js +157 -19
- package/dist/installer-electron.js +244 -77
- package/dist/installer-gui.js +243 -76
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
# Changelog — @leadbay/mcp
|
|
2
2
|
|
|
3
|
+
## 0.23.6 — 2026-06-25
|
|
4
|
+
|
|
5
|
+
Geographic filter on Discover lenses (product#3759).
|
|
6
|
+
|
|
7
|
+
- **`leadbay_new_lens` / `leadbay_adjust_audience`** now accept `locations` / `exclude_locations` — a geographic dimension on the Discover lens, mirroring the sector path. Free text (`["Indre-et-Loire"]`, `["Texas"]`) auto-resolves via `/geo/search`, or pass admin-area ids directly. Resolution happens first: ambiguous/unresolved text returns `ambiguous_locations` and the lens is **not** mutated (no half-built lens). Resolved ids merge into the lens filter as a `location_ids` criterion. Unblocks the "scope a territory → net-new accounts there" cockpit workflow — geography was previously settable only on the Monitor side.
|
|
8
|
+
|
|
3
9
|
## 0.23.3 — 2026-06-24
|
|
4
10
|
|
|
5
11
|
- **Release plumbing only** — no functional change. First release on the updated CI that also publishes fixed-name `leadbay-latest.dxt` / `.mcpb` assets, so the docs can link a stable `…/releases/latest/download/leadbay-latest.dxt` that always resolves to the current version.
|
package/dist/bin.js
CHANGED
|
@@ -5804,7 +5804,7 @@ This tool MUTATES state. The caller (agent or human-in-the-loop) is responsible
|
|
|
5804
5804
|
`;
|
|
5805
5805
|
leadbay_adjust_audience = `## WHEN TO USE
|
|
5806
5806
|
|
|
5807
|
-
Trigger phrases: "narrow the audience to <sector>", "add <sector> to my <name> lens", "remove <sector> from this lens", "only show me companies of <size>", "stop including <sector>", "broaden this lens to also include <sector>".
|
|
5807
|
+
Trigger phrases: "narrow the audience to <sector>", "add <sector> to my <name> lens", "remove <sector> from this lens", "only show me companies of <size>", "stop including <sector>", "broaden this lens to also include <sector>", "restrict this lens to <city/d\xE9partement/r\xE9gion/state>", "only companies in <place>", "exclude <region> from this lens".
|
|
5808
5808
|
|
|
5809
5809
|
**Memory:** recall + capture via \`leadbay_agent_memory_*\` tools.
|
|
5810
5810
|
|
|
@@ -5815,7 +5815,7 @@ Prefer when: user wants to change an EXISTING lens's sectors/sizes. If the user
|
|
|
5815
5815
|
Examples that SHOULD invoke this tool:
|
|
5816
5816
|
- "Add fintech to my Joinery lens."
|
|
5817
5817
|
- "Narrow my audience to manufacturing companies, 50\u2013500 people."
|
|
5818
|
-
- "
|
|
5818
|
+
- "Restrict my rep's lens to Indre-et-Loire."
|
|
5819
5819
|
|
|
5820
5820
|
Examples that should NOT invoke this tool (sound similar, route elsewhere):
|
|
5821
5821
|
- "Create a lens called Joinery for fintech."
|
|
@@ -5824,9 +5824,10 @@ Examples that should NOT invoke this tool (sound similar, route elsewhere):
|
|
|
5824
5824
|
|
|
5825
5825
|
## RENDER (quick)
|
|
5826
5826
|
|
|
5827
|
-
On \`applied\`: confirm the lens edited (name) + the sectors/sizes
|
|
5828
|
-
chips. On \`ambiguous_sectors\` / \`
|
|
5829
|
-
the candidates and ask the user
|
|
5827
|
+
On \`applied\`: confirm the lens edited (name) + the sectors/sizes/locations
|
|
5828
|
+
added as chips. On \`ambiguous_sectors\` / \`ambiguous_locations\` /
|
|
5829
|
+
\`ambiguous_lens\` / \`lens_not_found\`: surface the candidates and ask the user
|
|
5830
|
+
to pick, then re-call with the id/exact name.
|
|
5830
5831
|
|
|
5831
5832
|
---
|
|
5832
5833
|
|
|
@@ -5834,7 +5835,9 @@ Restrict (or expand) the lens audience by sector / size. Free-text sectors are a
|
|
|
5834
5835
|
|
|
5835
5836
|
**Targeting a lens \u2014 READ THIS.** By default this edits the user's ACTIVE lens. **If the user names a lens** ("add fintech to my **Joinery** lens", "in my Nordics lens, exclude retail"), you MUST pass \`lensName\` with that name (\`lensName:"Joinery"\`). Do NOT silently edit the active lens when a different one was named \u2014 that corrupts the wrong audience and is a top friction source. The name resolves against the user's lenses (case-insensitive, exact then unique-substring); it is edit-only and does NOT change which lens is active. An unmatched name returns \`status:"lens_not_found"\` with the lens list, and a name matching several returns \`status:"ambiguous_lens"\` with the candidates \u2014 surface them and re-call with the exact \`lensName\` or a \`lensId\`. Use \`leadbay_my_lenses\` if the user first wants to SEE or SWITCH lenses. To CREATE a brand-new lens, use \`leadbay_new_lens\` \u2014 not this tool.
|
|
5836
5837
|
|
|
5837
|
-
|
|
5838
|
+
**Geography \u2014 scope a sales territory.** Pass \`locations\` (free text like \`["Indre-et-Loire"]\`, \`["Bavaria"]\`, \`["Austin"]\`, or admin-area ids) to restrict the lens to a region, and \`exclude_locations\` to carve one out. Free text auto-resolves via \`/geo/search\` across every admin level \u2014 city, county, *d\xE9partement*, *r\xE9gion*, state, country. Place names go in \`locations\`, **never** in \`sectors\` or \`refine_prompt\`. Unresolved/ambiguous text returns \`status:"ambiguous_locations"\` with candidates \u2014 surface them and re-call the chosen id via the SAME axis it came from: an INCLUDE pick \u2192 \`location_ids\`; an EXCLUDE pick \u2192 \`exclude_locations\` (**NOT** \`location_ids\`, which would include the area the user asked to exclude). The returned \`message\` names the right param per text. This is how a director scopes a rep's territory and then asks for net-new accounts there.
|
|
5839
|
+
|
|
5840
|
+
WHEN TO USE: when the user wants to see different kinds of leads (sector / size / geography / etc.).
|
|
5838
5841
|
|
|
5839
5842
|
WHEN NOT TO USE: to refine BEYOND firmographics \u2014 that's leadbay_refine_prompt.
|
|
5840
5843
|
|
|
@@ -7382,7 +7385,7 @@ invent a tool that doesn't exist.
|
|
|
7382
7385
|
`;
|
|
7383
7386
|
leadbay_new_lens = `## WHEN TO USE
|
|
7384
7387
|
|
|
7385
|
-
Trigger phrases: "create a lens", "create a new lens called <name>", "create a lens specialized in/into <X>", "make me a new audience for <X>", "set up a lens for <sector>", "new lens named <name>", "I want a lens just for <X>".
|
|
7388
|
+
Trigger phrases: "create a lens", "create a new lens called <name>", "create a lens specialized in/into <X>", "make me a new audience for <X>", "set up a lens for <sector>", "new lens named <name>", "I want a lens just for <X>", "create a lens for net-new accounts in <place>", "a lens scoped to <territory>".
|
|
7386
7389
|
|
|
7387
7390
|
**Memory:** recall + capture via \`leadbay_agent_memory_*\` tools.
|
|
7388
7391
|
|
|
@@ -7393,7 +7396,7 @@ Prefer when: user wants a brand-new lens (create/make/set up, often 'specialized
|
|
|
7393
7396
|
Examples that SHOULD invoke this tool:
|
|
7394
7397
|
- "Create a lens called Joinery for the fintech sector."
|
|
7395
7398
|
- "Make me a new audience for healthcare companies, 30\u2013300 people."
|
|
7396
|
-
- "
|
|
7399
|
+
- "Create a lens for net-new accounts in Indre-et-Loire."
|
|
7397
7400
|
|
|
7398
7401
|
Examples that should NOT invoke this tool (sound similar, route elsewhere):
|
|
7399
7402
|
- "Add fintech to my Joinery lens."
|
|
@@ -7406,7 +7409,8 @@ On \`preview\` (default \u2014 NOTHING created yet): show the lens that WILL be
|
|
|
7406
7409
|
created (name + resolved sectors/sizes as chips) and ASK the user to confirm
|
|
7407
7410
|
via ask_user_input_v0 ("Create this lens?" / "Change something"). Only on
|
|
7408
7411
|
"yes" re-call with confirm:true. On \`created\`: confirm "Created **<name>**."
|
|
7409
|
-
On \`ambiguous_sectors\`: surface the
|
|
7412
|
+
On \`ambiguous_sectors\` / \`ambiguous_locations\`: surface the candidates to
|
|
7413
|
+
pick from.
|
|
7410
7414
|
|
|
7411
7415
|
---
|
|
7412
7416
|
|
|
@@ -7416,6 +7420,8 @@ Create a brand-new lens (saved audience) and apply its sector/size criteria. Clo
|
|
|
7416
7420
|
|
|
7417
7421
|
**Sectors resolve first.** Free-text \`sectors\`/\`exclude_sectors\` are auto-resolved against the taxonomy. If any don't resolve, the tool returns \`status:"ambiguous_sectors"\` with the candidates and **does NOT create the lens** \u2014 so re-calling after picking the right sector won't leave orphan half-built lenses. To discover valid sector labels up front, use \`leadbay_list_sectors\`.
|
|
7418
7422
|
|
|
7423
|
+
**Geography \u2014 scope a territory.** Pass \`locations\` (free text like \`["Indre-et-Loire"]\`, \`["Bavaria"]\`, or admin-area ids) to scope the lens to a sales territory, and \`exclude_locations\` to carve one out. Free text auto-resolves via \`/geo/search\` across every admin level (city / county / *d\xE9partement* / *r\xE9gion* / state / country). Like sectors, locations resolve BEFORE the lens is created \u2014 unresolved/ambiguous text returns \`status:"ambiguous_locations"\` with candidates and **does NOT create the lens**. Re-call the chosen id via the SAME axis it came from: an INCLUDE pick \u2192 \`locations\`; an EXCLUDE pick \u2192 \`exclude_locations\` (**NOT** \`locations\`, which would include the area the user asked to exclude). This is how a director spins up a lens for a rep's zone to surface net-new accounts there.
|
|
7424
|
+
|
|
7419
7425
|
**Does not switch the active lens.** The new lens is created but the user stays on their current one. Offer \`leadbay_my_lenses(switchToLensId=<new id>)\` as a next step if they want to start pulling from it.
|
|
7420
7426
|
|
|
7421
7427
|
WHEN TO USE: when the user wants a NEW lens. Canonical phrasings: "create a lens called X", "make a new audience for Y", "set up a lens for <sector>".
|
|
@@ -20616,7 +20622,7 @@ async function resolveLensByName(client, name) {
|
|
|
20616
20622
|
return { ok: false, reason: "ambiguous", matches: partial };
|
|
20617
20623
|
return { ok: false, reason: "not_found", lenses: all };
|
|
20618
20624
|
}
|
|
20619
|
-
function mergeFilter(current, toAddSectors, toExcludeSectors, sizes) {
|
|
20625
|
+
function mergeFilter(current, toAddSectors, toExcludeSectors, sizes, toAddLocations = [], toExcludeLocations = []) {
|
|
20620
20626
|
const items = current?.lens_filter?.items ?? [];
|
|
20621
20627
|
const item = items[0] ?? { criteria: [] };
|
|
20622
20628
|
const criteria = item.criteria ? [...item.criteria] : [];
|
|
@@ -20648,6 +20654,34 @@ function mergeFilter(current, toAddSectors, toExcludeSectors, sizes) {
|
|
|
20648
20654
|
});
|
|
20649
20655
|
}
|
|
20650
20656
|
}
|
|
20657
|
+
if (toAddLocations.length > 0) {
|
|
20658
|
+
const idx = criteria.findIndex((c) => c.type === "location_ids" && !c.is_excluded);
|
|
20659
|
+
if (idx >= 0) {
|
|
20660
|
+
const cur = criteria[idx];
|
|
20661
|
+
const merged = Array.from(/* @__PURE__ */ new Set([...cur.locations ?? [], ...toAddLocations]));
|
|
20662
|
+
criteria[idx] = { ...cur, locations: merged };
|
|
20663
|
+
} else {
|
|
20664
|
+
criteria.push({
|
|
20665
|
+
type: "location_ids",
|
|
20666
|
+
is_excluded: false,
|
|
20667
|
+
locations: toAddLocations
|
|
20668
|
+
});
|
|
20669
|
+
}
|
|
20670
|
+
}
|
|
20671
|
+
if (toExcludeLocations.length > 0) {
|
|
20672
|
+
const idx = criteria.findIndex((c) => c.type === "location_ids" && c.is_excluded);
|
|
20673
|
+
if (idx >= 0) {
|
|
20674
|
+
const cur = criteria[idx];
|
|
20675
|
+
const merged = Array.from(/* @__PURE__ */ new Set([...cur.locations ?? [], ...toExcludeLocations]));
|
|
20676
|
+
criteria[idx] = { ...cur, locations: merged };
|
|
20677
|
+
} else {
|
|
20678
|
+
criteria.push({
|
|
20679
|
+
type: "location_ids",
|
|
20680
|
+
is_excluded: true,
|
|
20681
|
+
locations: toExcludeLocations
|
|
20682
|
+
});
|
|
20683
|
+
}
|
|
20684
|
+
}
|
|
20651
20685
|
if (sizes && sizes.length > 0) {
|
|
20652
20686
|
const normalizedSizes = sizes.map((s) => ({
|
|
20653
20687
|
min: s.min ?? 0,
|
|
@@ -20672,6 +20706,7 @@ var adjustAudience;
|
|
|
20672
20706
|
var init_adjust_audience = __esm({
|
|
20673
20707
|
"../core/dist/composite/adjust-audience.js"() {
|
|
20674
20708
|
"use strict";
|
|
20709
|
+
init_geo_helpers();
|
|
20675
20710
|
init_tool_descriptions_generated();
|
|
20676
20711
|
adjustAudience = {
|
|
20677
20712
|
name: "leadbay_adjust_audience",
|
|
@@ -20713,6 +20748,21 @@ var init_adjust_audience = __esm({
|
|
|
20713
20748
|
},
|
|
20714
20749
|
description: "Company size buckets, e.g. [{min:30,max:300}]"
|
|
20715
20750
|
},
|
|
20751
|
+
locations: {
|
|
20752
|
+
type: "array",
|
|
20753
|
+
items: { type: "string" },
|
|
20754
|
+
description: "Geographic scope \u2014 free text (e.g. ['Indre-et-Loire', 'Bavaria', 'Austin']) or admin-area ids. Auto-resolved via /geo/search across all admin levels (city / county / d\xE9partement / r\xE9gion / state / country). Place names go HERE, never in sectors/keywords."
|
|
20755
|
+
},
|
|
20756
|
+
location_ids: {
|
|
20757
|
+
type: "array",
|
|
20758
|
+
items: { type: "string" },
|
|
20759
|
+
description: "Explicit admin-area ids (skips /geo/search resolution)"
|
|
20760
|
+
},
|
|
20761
|
+
exclude_locations: {
|
|
20762
|
+
type: "array",
|
|
20763
|
+
items: { type: "string" },
|
|
20764
|
+
description: "Locations to exclude (free text or ids)"
|
|
20765
|
+
},
|
|
20716
20766
|
lensId: { type: "number", description: "Lens id (escape hatch)" },
|
|
20717
20767
|
lensName: {
|
|
20718
20768
|
type: "string",
|
|
@@ -20731,17 +20781,22 @@ var init_adjust_audience = __esm({
|
|
|
20731
20781
|
},
|
|
20732
20782
|
outputSchema: {
|
|
20733
20783
|
type: "object",
|
|
20734
|
-
description: "Return shapes: 'applied' on success; 'ambiguous_sectors' when free-text sectors matched multiple candidates (re-call with sector_ids); 'lens_not_found' / 'ambiguous_lens' when a lensName didn't resolve to exactly one lens (re-call with lensId or an exact lensName).",
|
|
20784
|
+
description: "Return shapes: 'applied' on success; 'ambiguous_sectors' when free-text sectors matched multiple candidates (re-call with sector_ids); 'ambiguous_locations' when free-text locations didn't resolve to one area \u2014 re-call with the chosen id via the SAME axis it came from (an include pick \u2192 location_ids; an EXCLUDE pick \u2192 exclude_locations, NOT location_ids, which would include it); 'lens_not_found' / 'ambiguous_lens' when a lensName didn't resolve to exactly one lens (re-call with lensId or an exact lensName).",
|
|
20735
20785
|
properties: {
|
|
20736
20786
|
status: {
|
|
20737
20787
|
type: "string",
|
|
20738
|
-
description: "'applied', 'ambiguous_sectors', 'lens_not_found', or 'ambiguous_lens'."
|
|
20788
|
+
description: "'applied', 'ambiguous_sectors', 'ambiguous_locations', 'lens_not_found', or 'ambiguous_lens'."
|
|
20739
20789
|
},
|
|
20740
20790
|
sector_ambiguities: {
|
|
20741
20791
|
type: "array",
|
|
20742
20792
|
description: "Per ambiguous text: {sector_text, matches:[{id, name, score}]}. Agent picks an id and re-calls.",
|
|
20743
20793
|
items: { type: "object" }
|
|
20744
20794
|
},
|
|
20795
|
+
location_ambiguities: {
|
|
20796
|
+
type: "array",
|
|
20797
|
+
description: "On 'ambiguous_locations': per text {location_text, matches:[{id, name, country, level, score}]}. Agent picks an id and re-calls via the SAME axis the text came from \u2014 an include text \u2192 location_ids; a text from exclude_locations \u2192 exclude_locations (NOT location_ids, which would include the area the user asked to exclude). The `message` field names the correct param per text.",
|
|
20798
|
+
items: { type: "object" }
|
|
20799
|
+
},
|
|
20745
20800
|
lenses: {
|
|
20746
20801
|
type: "array",
|
|
20747
20802
|
description: "On 'lens_not_found': the user's lenses [{id, name}] to pick from.",
|
|
@@ -20825,9 +20880,45 @@ var init_adjust_audience = __esm({
|
|
|
20825
20880
|
message: parts.join(" ")
|
|
20826
20881
|
};
|
|
20827
20882
|
}
|
|
20883
|
+
const includeLocTexts = [
|
|
20884
|
+
...params.locations ?? [],
|
|
20885
|
+
...params.location_ids ?? []
|
|
20886
|
+
];
|
|
20887
|
+
const excludeLocTexts = params.exclude_locations ?? [];
|
|
20888
|
+
const includeLocRes = await resolveLocations(client, includeLocTexts);
|
|
20889
|
+
const excludeLocRes = await resolveLocations(client, excludeLocTexts);
|
|
20890
|
+
const locAmbiguities = [
|
|
20891
|
+
...includeLocRes.ambiguities,
|
|
20892
|
+
...excludeLocRes.ambiguities
|
|
20893
|
+
];
|
|
20894
|
+
if (locAmbiguities.length > 0) {
|
|
20895
|
+
const incMatch = includeLocRes.ambiguities.filter((a) => a.matches.length > 0);
|
|
20896
|
+
const incNone = includeLocRes.ambiguities.filter((a) => a.matches.length === 0);
|
|
20897
|
+
const excMatch = excludeLocRes.ambiguities.filter((a) => a.matches.length > 0);
|
|
20898
|
+
const excNone = excludeLocRes.ambiguities.filter((a) => a.matches.length === 0);
|
|
20899
|
+
const quote = (as) => as.map((a) => `"${a.location_text}"`).join(", ");
|
|
20900
|
+
const parts = [];
|
|
20901
|
+
if (incNone.length > 0) {
|
|
20902
|
+
parts.push(`Couldn't find a location matching ${quote(incNone)}. Ask the user to rephrase, then re-call with location_ids=...`);
|
|
20903
|
+
}
|
|
20904
|
+
if (incMatch.length > 0) {
|
|
20905
|
+
parts.push(`${quote(incMatch)} matched multiple areas. Pick from the matches and re-call with location_ids=...`);
|
|
20906
|
+
}
|
|
20907
|
+
if (excNone.length > 0) {
|
|
20908
|
+
parts.push(`Couldn't find a location to exclude matching ${quote(excNone)}. Ask the user to rephrase, then re-call with exclude_locations=... (the chosen id).`);
|
|
20909
|
+
}
|
|
20910
|
+
if (excMatch.length > 0) {
|
|
20911
|
+
parts.push(`${quote(excMatch)} (to exclude) matched multiple areas. Pick from the matches and re-call with exclude_locations=... (the chosen id) \u2014 NOT location_ids, which would include it.`);
|
|
20912
|
+
}
|
|
20913
|
+
return {
|
|
20914
|
+
status: "ambiguous_locations",
|
|
20915
|
+
location_ambiguities: locAmbiguities,
|
|
20916
|
+
message: parts.join(" ")
|
|
20917
|
+
};
|
|
20918
|
+
}
|
|
20828
20919
|
const lens = await client.request("GET", `/lenses/${startingLensId}`);
|
|
20829
20920
|
const currentFilter = await client.request("GET", `/lenses/${startingLensId}/filter`);
|
|
20830
|
-
const merged = mergeFilter(currentFilter, includeRes.resolved, excludeRes.resolved, params.sizes);
|
|
20921
|
+
const merged = mergeFilter(currentFilter, includeRes.resolved, excludeRes.resolved, params.sizes, includeLocRes.resolved, excludeLocRes.resolved);
|
|
20831
20922
|
const mergedBody = filterWriteBody(merged);
|
|
20832
20923
|
const isDefault = lens.is_default || lens.default;
|
|
20833
20924
|
const isUserLevel = lens.user_id != null;
|
|
@@ -21548,6 +21639,7 @@ var init_new_lens = __esm({
|
|
|
21548
21639
|
"../core/dist/composite/new-lens.js"() {
|
|
21549
21640
|
"use strict";
|
|
21550
21641
|
init_adjust_audience();
|
|
21642
|
+
init_geo_helpers();
|
|
21551
21643
|
init_tool_descriptions_generated();
|
|
21552
21644
|
EMPTY_FILTER = {
|
|
21553
21645
|
lens_filter: { items: [{ criteria: [] }] },
|
|
@@ -21586,6 +21678,16 @@ var init_new_lens = __esm({
|
|
|
21586
21678
|
},
|
|
21587
21679
|
description: "Company size buckets, e.g. [{min:30,max:300}]."
|
|
21588
21680
|
},
|
|
21681
|
+
locations: {
|
|
21682
|
+
type: "array",
|
|
21683
|
+
items: { type: "string" },
|
|
21684
|
+
description: "Geographic scope \u2014 free text (e.g. ['Indre-et-Loire', 'Bavaria']) or admin-area ids. Auto-resolved via /geo/search across all admin levels (city / county / d\xE9partement / r\xE9gion / state / country). Scopes the lens to a sales territory."
|
|
21685
|
+
},
|
|
21686
|
+
exclude_locations: {
|
|
21687
|
+
type: "array",
|
|
21688
|
+
items: { type: "string" },
|
|
21689
|
+
description: "Locations to exclude \u2014 free text or ids."
|
|
21690
|
+
},
|
|
21589
21691
|
base: {
|
|
21590
21692
|
type: "number",
|
|
21591
21693
|
description: "Lens id to clone from. Defaults to the active/default lens."
|
|
@@ -21601,12 +21703,12 @@ var init_new_lens = __esm({
|
|
|
21601
21703
|
},
|
|
21602
21704
|
outputSchema: {
|
|
21603
21705
|
type: "object",
|
|
21604
|
-
description: "'preview' (default, NOTHING created \u2014 confirm with the user then re-call with confirm:true); 'created' on success; 'ambiguous_sectors' when free-text sectors didn't resolve (re-call with
|
|
21706
|
+
description: "'preview' (default, NOTHING created \u2014 confirm with the user then re-call with confirm:true); 'created' on success; 'ambiguous_sectors' / 'ambiguous_locations' when free-text sectors / locations didn't resolve (re-call with ids \u2014 the lens was NOT created).",
|
|
21605
21707
|
properties: {
|
|
21606
|
-
status: { type: "string", description: "'preview', 'created', 'ambiguous_sectors', or 'orphan_created' (filter write failed + cleanup failed)." },
|
|
21708
|
+
status: { type: "string", description: "'preview', 'created', 'ambiguous_sectors', 'ambiguous_locations', or 'orphan_created' (filter write failed + cleanup failed)." },
|
|
21607
21709
|
will_create: {
|
|
21608
21710
|
type: "object",
|
|
21609
|
-
description: "On 'preview': what WILL be created \u2014 {name, description, sectors, exclude_sectors, sizes}. Nothing has been written yet."
|
|
21711
|
+
description: "On 'preview': what WILL be created \u2014 {name, description, sectors, exclude_sectors, sizes, locations, exclude_locations}. Nothing has been written yet."
|
|
21610
21712
|
},
|
|
21611
21713
|
filter_preview: { type: "object", description: "On 'preview': the FilterPayload that would be applied." },
|
|
21612
21714
|
lens: {
|
|
@@ -21618,6 +21720,11 @@ var init_new_lens = __esm({
|
|
|
21618
21720
|
description: "On 'ambiguous_sectors': per text {sector_text, matches:[{id,name,score}]}.",
|
|
21619
21721
|
items: { type: "object" }
|
|
21620
21722
|
},
|
|
21723
|
+
location_ambiguities: {
|
|
21724
|
+
type: "array",
|
|
21725
|
+
description: "On 'ambiguous_locations': per text {location_text, matches:[{id,name,country,level,score}]}. Re-call the chosen id via the SAME axis the text came from \u2014 an include text \u2192 locations; a text from exclude_locations \u2192 exclude_locations (NOT locations, which would include the area the user asked to exclude). The `message` field names the correct param per text.",
|
|
21726
|
+
items: { type: "object" }
|
|
21727
|
+
},
|
|
21621
21728
|
filter_applied: { type: "object", description: "On 'created': the FilterPayload POSTed to the new lens." },
|
|
21622
21729
|
message: { type: "string" },
|
|
21623
21730
|
_meta: { type: "object" }
|
|
@@ -21644,7 +21751,38 @@ var init_new_lens = __esm({
|
|
|
21644
21751
|
message: parts.join(" ")
|
|
21645
21752
|
};
|
|
21646
21753
|
}
|
|
21647
|
-
const
|
|
21754
|
+
const includeLocRes = await resolveLocations(client, params.locations ?? []);
|
|
21755
|
+
const excludeLocRes = await resolveLocations(client, params.exclude_locations ?? []);
|
|
21756
|
+
const locAmbiguities = [
|
|
21757
|
+
...includeLocRes.ambiguities,
|
|
21758
|
+
...excludeLocRes.ambiguities
|
|
21759
|
+
];
|
|
21760
|
+
if (locAmbiguities.length > 0) {
|
|
21761
|
+
const incMatch = includeLocRes.ambiguities.filter((a) => a.matches.length > 0);
|
|
21762
|
+
const incNone = includeLocRes.ambiguities.filter((a) => a.matches.length === 0);
|
|
21763
|
+
const excMatch = excludeLocRes.ambiguities.filter((a) => a.matches.length > 0);
|
|
21764
|
+
const excNone = excludeLocRes.ambiguities.filter((a) => a.matches.length === 0);
|
|
21765
|
+
const quote = (as) => as.map((a) => `"${a.location_text}"`).join(", ");
|
|
21766
|
+
const parts = [];
|
|
21767
|
+
if (incNone.length > 0) {
|
|
21768
|
+
parts.push(`Couldn't find a location matching ${quote(incNone)}. Pick a known area and re-call via locations (lens not yet created).`);
|
|
21769
|
+
}
|
|
21770
|
+
if (incMatch.length > 0) {
|
|
21771
|
+
parts.push(`${quote(incMatch)} matched multiple areas. Pick from the matches and re-call with the chosen id in locations.`);
|
|
21772
|
+
}
|
|
21773
|
+
if (excNone.length > 0) {
|
|
21774
|
+
parts.push(`Couldn't find a location to exclude matching ${quote(excNone)}. Pick a known area and re-call via exclude_locations (lens not yet created).`);
|
|
21775
|
+
}
|
|
21776
|
+
if (excMatch.length > 0) {
|
|
21777
|
+
parts.push(`${quote(excMatch)} (to exclude) matched multiple areas. Pick from the matches and re-call with the chosen id in exclude_locations \u2014 NOT locations, which would include it.`);
|
|
21778
|
+
}
|
|
21779
|
+
return {
|
|
21780
|
+
status: "ambiguous_locations",
|
|
21781
|
+
location_ambiguities: locAmbiguities,
|
|
21782
|
+
message: parts.join(" ")
|
|
21783
|
+
};
|
|
21784
|
+
}
|
|
21785
|
+
const merged = mergeFilter(EMPTY_FILTER, includeRes.resolved, excludeRes.resolved, params.sizes, includeLocRes.resolved, excludeLocRes.resolved);
|
|
21648
21786
|
if (params.confirm !== true) {
|
|
21649
21787
|
return {
|
|
21650
21788
|
status: "preview",
|
|
@@ -21653,7 +21791,9 @@ var init_new_lens = __esm({
|
|
|
21653
21791
|
description: params.description ?? null,
|
|
21654
21792
|
sectors: includeRes.resolved,
|
|
21655
21793
|
exclude_sectors: excludeRes.resolved,
|
|
21656
|
-
sizes: merged.lens_filter.items[0].criteria.find((c) => c.type === "size") ?? null
|
|
21794
|
+
sizes: merged.lens_filter.items[0].criteria.find((c) => c.type === "size") ?? null,
|
|
21795
|
+
locations: includeLocRes.resolved,
|
|
21796
|
+
exclude_locations: excludeLocRes.resolved
|
|
21657
21797
|
},
|
|
21658
21798
|
filter_preview: merged,
|
|
21659
21799
|
message: `About to create "${params.name}". Confirm with the user, then re-call with confirm:true.`,
|
|
@@ -26059,7 +26199,7 @@ ${url}
|
|
|
26059
26199
|
|
|
26060
26200
|
// installer/install-shared.ts
|
|
26061
26201
|
import { spawn } from "child_process";
|
|
26062
|
-
import { existsSync as existsSync2, readFileSync as readFileSync2 } from "fs";
|
|
26202
|
+
import { existsSync as existsSync2, readFileSync as readFileSync2, readdirSync as readdirSync2 } from "fs";
|
|
26063
26203
|
import { join as join3 } from "path";
|
|
26064
26204
|
import { homedir as homedir3 } from "os";
|
|
26065
26205
|
var HOSTED_MCP_URL = "https://leadbay-mcp-prod.fly.dev/mcp";
|
|
@@ -26116,6 +26256,15 @@ async function windowsStoreAppInstalled(packageName, appName) {
|
|
|
26116
26256
|
child.on("error", () => resolve(false));
|
|
26117
26257
|
});
|
|
26118
26258
|
}
|
|
26259
|
+
function isClaudeStorePackagePresent(localAppData) {
|
|
26260
|
+
const packagesDir = join3(localAppData, "Packages");
|
|
26261
|
+
if (!existsSync2(packagesDir)) return false;
|
|
26262
|
+
try {
|
|
26263
|
+
return readdirSync2(packagesDir).some((name) => /^Claude_/i.test(name));
|
|
26264
|
+
} catch {
|
|
26265
|
+
return false;
|
|
26266
|
+
}
|
|
26267
|
+
}
|
|
26119
26268
|
async function isClaudeDesktopInstalled(home) {
|
|
26120
26269
|
if (process.platform === "darwin") {
|
|
26121
26270
|
return existsSync2("/Applications/Claude.app") || existsSync2(home + "/Applications/Claude.app");
|
|
@@ -26124,12 +26273,15 @@ async function isClaudeDesktopInstalled(home) {
|
|
|
26124
26273
|
const local = process.env.LOCALAPPDATA ?? home + "/AppData/Local";
|
|
26125
26274
|
const programFiles = process.env.ProgramFiles;
|
|
26126
26275
|
const programFilesX86 = process.env["ProgramFiles(x86)"];
|
|
26127
|
-
|
|
26276
|
+
const exeInstalled = [
|
|
26128
26277
|
local + "/Programs/Claude/Claude.exe",
|
|
26129
26278
|
local + "/Claude/Claude.exe",
|
|
26130
26279
|
programFiles ? programFiles + "/Claude/Claude.exe" : null,
|
|
26131
26280
|
programFilesX86 ? programFilesX86 + "/Claude/Claude.exe" : null
|
|
26132
26281
|
].some((candidate) => candidate !== null && existsSync2(candidate));
|
|
26282
|
+
if (exeInstalled) return true;
|
|
26283
|
+
if (isClaudeStorePackagePresent(local)) return true;
|
|
26284
|
+
return await windowsStoreAppInstalled("AnthropicPBC.Claude", "Claude");
|
|
26133
26285
|
}
|
|
26134
26286
|
const desktopBin = await findOnPath("claude-desktop");
|
|
26135
26287
|
if (desktopBin) return true;
|
|
@@ -26936,7 +27088,7 @@ import { createHash as createHash5, randomBytes } from "crypto";
|
|
|
26936
27088
|
import { createServer } from "http";
|
|
26937
27089
|
import { request as httpsRequestRaw } from "https";
|
|
26938
27090
|
import { spawn as spawn3 } from "child_process";
|
|
26939
|
-
import { readdirSync as
|
|
27091
|
+
import { readdirSync as readdirSync3, existsSync as existsSync3 } from "fs";
|
|
26940
27092
|
var LEADBAY_LOOPBACK_PORTS = [51789, 51790, 51791, 51792];
|
|
26941
27093
|
var BrowserOpenFailedError = class extends Error {
|
|
26942
27094
|
authorizeUrl;
|
|
@@ -27272,7 +27424,7 @@ function browserLaunchEnv(debug) {
|
|
|
27272
27424
|
}
|
|
27273
27425
|
if (!env.WAYLAND_DISPLAY && runtimeDir) {
|
|
27274
27426
|
try {
|
|
27275
|
-
const sock =
|
|
27427
|
+
const sock = readdirSync3(runtimeDir).find((f) => /^wayland-\d+$/.test(f));
|
|
27276
27428
|
if (sock) {
|
|
27277
27429
|
env.WAYLAND_DISPLAY = sock;
|
|
27278
27430
|
debug?.(`browserLaunchEnv: injected WAYLAND_DISPLAY=${sock}`);
|
|
@@ -27289,7 +27441,7 @@ function browserLaunchEnv(debug) {
|
|
|
27289
27441
|
}
|
|
27290
27442
|
if (!env.DISPLAY) {
|
|
27291
27443
|
try {
|
|
27292
|
-
const x =
|
|
27444
|
+
const x = readdirSync3("/tmp/.X11-unix").map((f) => f.match(/^X(\d+)$/)?.[1]).filter((n) => !!n).sort((a, b) => Number(a) - Number(b))[0];
|
|
27293
27445
|
env.DISPLAY = x !== void 0 ? `:${x}` : ":0";
|
|
27294
27446
|
} catch {
|
|
27295
27447
|
env.DISPLAY = ":0";
|
|
@@ -27300,7 +27452,7 @@ function browserLaunchEnv(debug) {
|
|
|
27300
27452
|
try {
|
|
27301
27453
|
let xauth;
|
|
27302
27454
|
if (runtimeDir) {
|
|
27303
|
-
const cookie =
|
|
27455
|
+
const cookie = readdirSync3(runtimeDir).find(
|
|
27304
27456
|
(f) => /^\.mutter-Xwaylandauth\./.test(f)
|
|
27305
27457
|
);
|
|
27306
27458
|
if (cookie) xauth = `${runtimeDir}/${cookie}`;
|
|
@@ -27439,7 +27591,7 @@ var OAUTH_BASE_URLS = {
|
|
|
27439
27591
|
fr: "https://staging.api.leadbay.app"
|
|
27440
27592
|
}
|
|
27441
27593
|
};
|
|
27442
|
-
var VERSION = "0.23.
|
|
27594
|
+
var VERSION = "0.23.6";
|
|
27443
27595
|
var HELP = `
|
|
27444
27596
|
leadbay-mcp ${VERSION} \u2014 Leadbay Model Context Protocol server
|
|
27445
27597
|
|