@canonry/canonry 4.136.0 → 4.136.2
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/assets/agent-workspace/skills/canonry/references/canonry-cli.md +4 -0
- package/assets/agent-workspace/skills/canonry/references/indexing.md +26 -12
- package/assets/assets/{AuditHistoryPanel-DKaiIlcO.js → AuditHistoryPanel-DtUGiN21.js} +1 -1
- package/assets/assets/{BacklinksPage-Z2_ws8c2.js → BacklinksPage-BGwtmwfz.js} +1 -1
- package/assets/assets/{ChartPrimitives-CF_ocuvj.js → ChartPrimitives-Df2UC1g3.js} +1 -1
- package/assets/assets/{HistoryPage-DDKO8_D8.js → HistoryPage-AtaMVEUx.js} +1 -1
- package/assets/assets/ProjectPage-OlBjxXNx.js +8 -0
- package/assets/assets/{RunRow-BhtCgyqA.js → RunRow-Cmf-5xVo.js} +1 -1
- package/assets/assets/{RunsPage-B8Nw3wP-.js → RunsPage-BAPy9Yri.js} +1 -1
- package/assets/assets/{SettingsPage-DsmQhytl.js → SettingsPage-BXO7WpTo.js} +1 -1
- package/assets/assets/{TrafficPage-COJs6eRH.js → TrafficPage-IH-wiPu2.js} +1 -1
- package/assets/assets/{TrafficSourceDetailPage-BI6IwzMQ.js → TrafficSourceDetailPage-CTTN-P52.js} +1 -1
- package/assets/assets/{arrow-left-C-lGPq-u.js → arrow-left-BwzAIeJ_.js} +1 -1
- package/assets/assets/{extract-error-message-8h0hF1I1.js → extract-error-message-BIcIoJLN.js} +1 -1
- package/assets/assets/index-BPpSrJY0.js +210 -0
- package/assets/assets/index-CglduHCN.css +1 -0
- package/assets/assets/{trash-2-CnOZwYKe.js → trash-2-C50OeBAV.js} +1 -1
- package/assets/index.html +2 -2
- package/dist/{chunk-PXEEWJRV.js → chunk-GGIRLRAY.js} +3093 -399
- package/dist/{chunk-3PFRVEWP.js → chunk-MXR3GI5L.js} +54 -122
- package/dist/{chunk-PAR6P5H6.js → chunk-SMFUCXHI.js} +132 -6
- package/dist/{chunk-TPVMHYHD.js → chunk-YVMQWVNY.js} +291 -206
- package/dist/cli.js +184 -15
- package/dist/index.js +4 -4
- package/dist/{intelligence-service-BMEJ5GFZ.js → intelligence-service-BD6BHTEJ.js} +2 -2
- package/dist/mcp.js +2 -2
- package/package.json +9 -9
- package/assets/assets/ProjectPage-hmNsqBov.js +0 -8
- package/assets/assets/index-B4ksyQXo.css +0 -1
- package/assets/assets/index-BoSfFv1t.js +0 -210
|
@@ -10,7 +10,7 @@ import {
|
|
|
10
10
|
loadConfig,
|
|
11
11
|
loadConfigRaw,
|
|
12
12
|
saveConfigPatch
|
|
13
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-SMFUCXHI.js";
|
|
14
14
|
import {
|
|
15
15
|
CC_CACHE_DIR,
|
|
16
16
|
DUCKDB_SPEC,
|
|
@@ -119,7 +119,7 @@ import {
|
|
|
119
119
|
siteAuditPages,
|
|
120
120
|
siteAuditSnapshots,
|
|
121
121
|
usageCounters
|
|
122
|
-
} from "./chunk-
|
|
122
|
+
} from "./chunk-YVMQWVNY.js";
|
|
123
123
|
import {
|
|
124
124
|
AGENT_MEMORY_VALUE_MAX_BYTES,
|
|
125
125
|
AGENT_PROVIDER_IDS,
|
|
@@ -173,6 +173,8 @@ import {
|
|
|
173
173
|
factorStatusFromScore,
|
|
174
174
|
formatIsoDateInTimeZone,
|
|
175
175
|
frameAncestorsHeaderValue,
|
|
176
|
+
hostMatchesAnyDomain,
|
|
177
|
+
hostMatchesDomain,
|
|
176
178
|
hostOf,
|
|
177
179
|
isAgentProviderId,
|
|
178
180
|
isBrowserProvider,
|
|
@@ -185,16 +187,19 @@ import {
|
|
|
185
187
|
notFound,
|
|
186
188
|
parseOriginList,
|
|
187
189
|
providerError,
|
|
190
|
+
registrableDomain,
|
|
188
191
|
resolveSnapshotRequestQueries,
|
|
189
192
|
serializeForInlineScript,
|
|
190
193
|
serializeRunError,
|
|
191
194
|
skillsClientSchema,
|
|
192
195
|
splitList,
|
|
193
196
|
startOfDayHourInTimeZone,
|
|
197
|
+
textContainsBrandAlias,
|
|
198
|
+
textContainsDomain,
|
|
194
199
|
validationError,
|
|
195
200
|
winnabilityClassLabel,
|
|
196
201
|
withRetry
|
|
197
|
-
} from "./chunk-
|
|
202
|
+
} from "./chunk-GGIRLRAY.js";
|
|
198
203
|
|
|
199
204
|
// src/telemetry.ts
|
|
200
205
|
import crypto from "crypto";
|
|
@@ -728,17 +733,15 @@ function extractCitedDomainsFromSources(groundingSources) {
|
|
|
728
733
|
return [...domains];
|
|
729
734
|
}
|
|
730
735
|
function extractDomainFromTitle(title) {
|
|
731
|
-
const trimmed = title.trim()
|
|
732
|
-
|
|
733
|
-
return trimmed.replace(/^www\./, "");
|
|
734
|
-
}
|
|
735
|
-
return null;
|
|
736
|
+
const trimmed = title.trim();
|
|
737
|
+
return registrableDomain(trimmed) ? hostOf(trimmed) : null;
|
|
736
738
|
}
|
|
737
739
|
function extractDomainFromUri(uri) {
|
|
738
740
|
try {
|
|
739
741
|
const url = new URL(uri);
|
|
740
|
-
const hostname =
|
|
741
|
-
if (
|
|
742
|
+
const hostname = hostOf(uri);
|
|
743
|
+
if (!hostname || !registrableDomain(hostname)) return null;
|
|
744
|
+
if (hostMatchesAnyDomain(hostname, AI_ENGINE_SELF_DOMAINS.chatgpt)) {
|
|
742
745
|
return null;
|
|
743
746
|
}
|
|
744
747
|
if (hostname === VERTEX_AI_SEARCH_PROXY_DOMAIN) {
|
|
@@ -747,8 +750,7 @@ function extractDomainFromUri(uri) {
|
|
|
747
750
|
try {
|
|
748
751
|
const decoded = decodeURIComponent(redirectPath);
|
|
749
752
|
if (decoded.startsWith("http")) {
|
|
750
|
-
|
|
751
|
-
return realUrl.hostname.replace(/^www\./, "");
|
|
753
|
+
return hostOf(decoded);
|
|
752
754
|
}
|
|
753
755
|
} catch {
|
|
754
756
|
}
|
|
@@ -1169,16 +1171,9 @@ function extractCitedDomainsFromSources2(groundingSources) {
|
|
|
1169
1171
|
return [...domains];
|
|
1170
1172
|
}
|
|
1171
1173
|
function extractDomainFromUri2(uri) {
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
if (AI_ENGINE_SELF_DOMAINS.chatgpt.some((self) => hostname.includes(self))) {
|
|
1176
|
-
return null;
|
|
1177
|
-
}
|
|
1178
|
-
return hostname;
|
|
1179
|
-
} catch {
|
|
1180
|
-
return null;
|
|
1181
|
-
}
|
|
1174
|
+
const hostname = hostOf(uri);
|
|
1175
|
+
if (!hostname || !registrableDomain(hostname) || hostMatchesAnyDomain(hostname, AI_ENGINE_SELF_DOMAINS.chatgpt)) return null;
|
|
1176
|
+
return hostname;
|
|
1182
1177
|
}
|
|
1183
1178
|
async function generateText2(prompt, config) {
|
|
1184
1179
|
const model = config.model ?? DEFAULT_MODEL2;
|
|
@@ -1538,16 +1533,11 @@ function extractCitedDomainsFromSources3(groundingSources) {
|
|
|
1538
1533
|
return [...domains];
|
|
1539
1534
|
}
|
|
1540
1535
|
function extractDomainFromUri3(uri) {
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
const hostname = url.hostname.replace(/^www\./, "").toLowerCase();
|
|
1544
|
-
if (AI_ENGINE_SELF_DOMAINS.chatgpt.some((self) => hostname.includes(self))) {
|
|
1545
|
-
return null;
|
|
1546
|
-
}
|
|
1547
|
-
return hostname;
|
|
1548
|
-
} catch {
|
|
1536
|
+
const hostname = hostOf(uri);
|
|
1537
|
+
if (!hostname || !registrableDomain(hostname) || hostMatchesAnyDomain(hostname, AI_ENGINE_SELF_DOMAINS.chatgpt)) {
|
|
1549
1538
|
return null;
|
|
1550
1539
|
}
|
|
1540
|
+
return hostname;
|
|
1551
1541
|
}
|
|
1552
1542
|
async function generateText3(prompt, config) {
|
|
1553
1543
|
const model = resolveModel2(config);
|
|
@@ -1755,11 +1745,10 @@ async function executeTrackedQuery4(input) {
|
|
|
1755
1745
|
}
|
|
1756
1746
|
function normalizeResult4(raw) {
|
|
1757
1747
|
const answerText = extractAnswerText2(raw.rawResponse);
|
|
1758
|
-
const
|
|
1759
|
-
const
|
|
1760
|
-
uri
|
|
1761
|
-
|
|
1762
|
-
}));
|
|
1748
|
+
const groundingSources = raw.groundingSources;
|
|
1749
|
+
const citedDomains = [...new Set(
|
|
1750
|
+
groundingSources.map((source) => hostOf(source.uri)).filter((domain) => domain !== null && registrableDomain(domain).length > 0)
|
|
1751
|
+
)];
|
|
1763
1752
|
return {
|
|
1764
1753
|
provider: "local",
|
|
1765
1754
|
answerText,
|
|
@@ -1795,19 +1784,6 @@ async function generateText4(prompt, config) {
|
|
|
1795
1784
|
);
|
|
1796
1785
|
return response.choices[0]?.message?.content ?? "";
|
|
1797
1786
|
}
|
|
1798
|
-
function extractDomainMentions(text) {
|
|
1799
|
-
const domains = /* @__PURE__ */ new Set();
|
|
1800
|
-
const urlPattern = /https?:\/\/([a-zA-Z0-9][-a-zA-Z0-9]*(?:\.[a-zA-Z0-9][-a-zA-Z0-9]*)+)/g;
|
|
1801
|
-
let match;
|
|
1802
|
-
while ((match = urlPattern.exec(text)) !== null) {
|
|
1803
|
-
domains.add(match[1].replace(/^www\./, "").toLowerCase());
|
|
1804
|
-
}
|
|
1805
|
-
const domainPattern = /(?:^|[\s(["'])((?:[a-zA-Z0-9][-a-zA-Z0-9]*\.)+(?:com|org|net|io|co|dev|ai|app|edu|gov|biz|info|tech|health|dental|legal|law|med|uk|us|ca|au|de|fr|es|it|nl|se|no|dk|fi|jp|cn|kr|br|mx|ru|in|sg|nz|za)(?:\.[a-zA-Z]{2})?)(?:[\s).,;/"']|$)/g;
|
|
1806
|
-
while ((match = domainPattern.exec(text)) !== null) {
|
|
1807
|
-
domains.add(match[1].replace(/^www\./, "").toLowerCase());
|
|
1808
|
-
}
|
|
1809
|
-
return [...domains];
|
|
1810
|
-
}
|
|
1811
1787
|
function extractServedModel4(rawResponse) {
|
|
1812
1788
|
return normalizeServedModel(rawResponse.model);
|
|
1813
1789
|
}
|
|
@@ -2186,6 +2162,9 @@ var chatgptTarget = {
|
|
|
2186
2162
|
const { result } = await client.Runtime.evaluate({
|
|
2187
2163
|
expression: `(() => {
|
|
2188
2164
|
const SELF_DOMAINS = ${selfDomainsLiteral};
|
|
2165
|
+
const isSelfDomain = hostname => SELF_DOMAINS.some(
|
|
2166
|
+
self => hostname === self || hostname.endsWith('.' + self)
|
|
2167
|
+
);
|
|
2189
2168
|
const sources = [];
|
|
2190
2169
|
const seen = new Set();
|
|
2191
2170
|
const turns = document.querySelectorAll('[data-message-author-role="assistant"]');
|
|
@@ -2209,7 +2188,7 @@ var chatgptTarget = {
|
|
|
2209
2188
|
}
|
|
2210
2189
|
}
|
|
2211
2190
|
|
|
2212
|
-
if (!seen.has(href) && !
|
|
2191
|
+
if (!seen.has(href) && !isSelfDomain(hostname)) {
|
|
2213
2192
|
seen.add(href);
|
|
2214
2193
|
sources.push({
|
|
2215
2194
|
uri: href,
|
|
@@ -2226,7 +2205,7 @@ var chatgptTarget = {
|
|
|
2226
2205
|
if (href && !seen.has(href)) {
|
|
2227
2206
|
let hostname = '';
|
|
2228
2207
|
try { hostname = new URL(href).hostname.replace(/^www\\./, ''); } catch {}
|
|
2229
|
-
if (!
|
|
2208
|
+
if (!isSelfDomain(hostname)) {
|
|
2230
2209
|
seen.add(href);
|
|
2231
2210
|
sources.push({ uri: href, title: title || hostname || href });
|
|
2232
2211
|
}
|
|
@@ -2313,13 +2292,10 @@ async function captureElementScreenshot(client, selector, outputPath) {
|
|
|
2313
2292
|
function extractCitedDomains(groundingSources) {
|
|
2314
2293
|
const domains = /* @__PURE__ */ new Set();
|
|
2315
2294
|
for (const source of groundingSources) {
|
|
2316
|
-
|
|
2317
|
-
|
|
2318
|
-
|
|
2319
|
-
|
|
2320
|
-
domains.add(domain);
|
|
2321
|
-
}
|
|
2322
|
-
} catch {
|
|
2295
|
+
const domain = hostOf(source.uri);
|
|
2296
|
+
if (domain && registrableDomain(domain)) {
|
|
2297
|
+
if (!hostMatchesAnyDomain(domain, AI_ENGINE_SELF_DOMAINS.chatgpt)) domains.add(domain);
|
|
2298
|
+
} else {
|
|
2323
2299
|
const titleDomain = extractDomainFromTitle2(source.title);
|
|
2324
2300
|
if (titleDomain) domains.add(titleDomain);
|
|
2325
2301
|
}
|
|
@@ -2327,12 +2303,9 @@ function extractCitedDomains(groundingSources) {
|
|
|
2327
2303
|
return [...domains];
|
|
2328
2304
|
}
|
|
2329
2305
|
function extractDomainFromTitle2(title) {
|
|
2330
|
-
const domainPattern = /^(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z]{2,}$/i;
|
|
2331
2306
|
const firstWord = title.split(/[\s\-–—|]/)[0]?.trim();
|
|
2332
|
-
if (firstWord
|
|
2333
|
-
|
|
2334
|
-
}
|
|
2335
|
-
return void 0;
|
|
2307
|
+
if (!firstWord || !registrableDomain(firstWord)) return void 0;
|
|
2308
|
+
return hostOf(firstWord) ?? void 0;
|
|
2336
2309
|
}
|
|
2337
2310
|
function normalizeResult5(raw) {
|
|
2338
2311
|
const answerText = typeof raw.rawResponse.answerText === "string" ? raw.rawResponse.answerText : "";
|
|
@@ -2685,16 +2658,9 @@ function extractCitedDomains2(groundingSources) {
|
|
|
2685
2658
|
return [...domains];
|
|
2686
2659
|
}
|
|
2687
2660
|
function extractDomainFromUri4(uri) {
|
|
2688
|
-
|
|
2689
|
-
|
|
2690
|
-
|
|
2691
|
-
if (AI_ENGINE_SELF_DOMAINS.chatgpt.some((self) => hostname.includes(self))) {
|
|
2692
|
-
return null;
|
|
2693
|
-
}
|
|
2694
|
-
return hostname;
|
|
2695
|
-
} catch {
|
|
2696
|
-
return null;
|
|
2697
|
-
}
|
|
2661
|
+
const hostname = hostOf(uri);
|
|
2662
|
+
if (!hostname || !registrableDomain(hostname) || hostMatchesAnyDomain(hostname, AI_ENGINE_SELF_DOMAINS.chatgpt)) return null;
|
|
2663
|
+
return hostname;
|
|
2698
2664
|
}
|
|
2699
2665
|
async function generateText5(prompt, config) {
|
|
2700
2666
|
const model = config.model ?? DEFAULT_MODEL5;
|
|
@@ -5930,7 +5896,7 @@ function aggregateInboundLinksByDomain(links, targetDomain) {
|
|
|
5930
5896
|
for (const link of links) {
|
|
5931
5897
|
const host = hostOf(link.Url);
|
|
5932
5898
|
if (!host) continue;
|
|
5933
|
-
if (target && (host
|
|
5899
|
+
if (target && hostMatchesDomain(host, target)) continue;
|
|
5934
5900
|
let urls = byHost.get(host);
|
|
5935
5901
|
if (!urls) {
|
|
5936
5902
|
urls = /* @__PURE__ */ new Set();
|
|
@@ -7066,7 +7032,7 @@ function readStoredGroundingSources(rawResponse) {
|
|
|
7066
7032
|
return result;
|
|
7067
7033
|
}
|
|
7068
7034
|
async function backfillInsightsCommand(project, opts) {
|
|
7069
|
-
const { IntelligenceService: IntelligenceService2 } = await import("./intelligence-service-
|
|
7035
|
+
const { IntelligenceService: IntelligenceService2 } = await import("./intelligence-service-BD6BHTEJ.js");
|
|
7070
7036
|
const config = loadConfig();
|
|
7071
7037
|
const db = createClient(config.database);
|
|
7072
7038
|
migrate(db);
|
|
@@ -10899,16 +10865,6 @@ var FETCH_TIMEOUT_MS2 = 1e4;
|
|
|
10899
10865
|
var MAX_TEXT_LENGTH = 4e3;
|
|
10900
10866
|
var MAX_BODY_BYTES = 512e3;
|
|
10901
10867
|
var USER_AGENT = "Canonry/1.0 (site-analysis)";
|
|
10902
|
-
function extractHostname(domain) {
|
|
10903
|
-
let hostname = domain;
|
|
10904
|
-
try {
|
|
10905
|
-
if (hostname.includes("://")) {
|
|
10906
|
-
hostname = new URL(hostname).hostname;
|
|
10907
|
-
}
|
|
10908
|
-
} catch {
|
|
10909
|
-
}
|
|
10910
|
-
return hostname.replace(/^www\./, "");
|
|
10911
|
-
}
|
|
10912
10868
|
function fetchWithPinnedAddress(target) {
|
|
10913
10869
|
return new Promise((resolve) => {
|
|
10914
10870
|
const port = target.url.port ? Number(target.url.port) : 443;
|
|
@@ -10965,7 +10921,8 @@ function fetchWithPinnedAddress(target) {
|
|
|
10965
10921
|
});
|
|
10966
10922
|
}
|
|
10967
10923
|
async function fetchSiteText(domain) {
|
|
10968
|
-
const hostname =
|
|
10924
|
+
const hostname = hostOf(domain);
|
|
10925
|
+
if (!hostname) return "";
|
|
10969
10926
|
const url = `https://${hostname}`;
|
|
10970
10927
|
const targetCheck = await resolveWebhookTarget(url);
|
|
10971
10928
|
if (!targetCheck.ok) return "";
|
|
@@ -11084,7 +11041,7 @@ var SnapshotService = class {
|
|
|
11084
11041
|
registry;
|
|
11085
11042
|
async createReport(input) {
|
|
11086
11043
|
const companyName = input.companyName.trim();
|
|
11087
|
-
const domain =
|
|
11044
|
+
const domain = hostOf(input.domain) ?? input.domain.trim();
|
|
11088
11045
|
const manualQueries = normalizeStringList(resolveSnapshotRequestQueries(input));
|
|
11089
11046
|
const manualCompetitors = normalizeStringList(input.competitors ?? []);
|
|
11090
11047
|
const providers = this.registry.getAll();
|
|
@@ -11092,14 +11049,14 @@ var SnapshotService = class {
|
|
|
11092
11049
|
throw new Error("No providers configured. Add at least one provider API key before running canonry snapshot.");
|
|
11093
11050
|
}
|
|
11094
11051
|
const analysisProvider = pickAnalysisProvider(this.registry.getApiProviders());
|
|
11095
|
-
const homepageUrl = `https://${
|
|
11052
|
+
const homepageUrl = `https://${domain}`;
|
|
11096
11053
|
const [siteText, audit] = await Promise.all([
|
|
11097
11054
|
fetchSiteText(domain),
|
|
11098
11055
|
this.runAudit(homepageUrl)
|
|
11099
11056
|
]);
|
|
11100
11057
|
if (manualQueries.length === 0 && !siteText) {
|
|
11101
11058
|
throw new Error(
|
|
11102
|
-
`Could not analyze https://${
|
|
11059
|
+
`Could not analyze https://${domain}. Try again with a reachable homepage or pass manual category queries via --queries.`
|
|
11103
11060
|
);
|
|
11104
11061
|
}
|
|
11105
11062
|
const profile = await this.buildProfile({
|
|
@@ -11501,36 +11458,30 @@ function buildFallbackRecommendedActions(audit) {
|
|
|
11501
11458
|
return uniqueStrings([...weakestFactors, ...defaults]).slice(0, 4);
|
|
11502
11459
|
}
|
|
11503
11460
|
function citesTargetDomain(citedDomains, groundingSources, targetDomain) {
|
|
11504
|
-
const normalizedTarget = extractHostname2(targetDomain);
|
|
11505
11461
|
for (const domain of citedDomains) {
|
|
11506
|
-
if (
|
|
11462
|
+
if (hostMatchesDomain(domain, targetDomain)) {
|
|
11507
11463
|
return true;
|
|
11508
11464
|
}
|
|
11509
11465
|
}
|
|
11510
11466
|
for (const source of groundingSources) {
|
|
11511
|
-
if (source.uri
|
|
11512
|
-
|
|
11513
|
-
}
|
|
11514
|
-
if (source.title && source.title.toLowerCase().includes(normalizedTarget.toLowerCase())) {
|
|
11515
|
-
return true;
|
|
11516
|
-
}
|
|
11467
|
+
if (hostMatchesDomain(source.uri, targetDomain)) return true;
|
|
11468
|
+
if (source.title && hostMatchesDomain(source.title, targetDomain)) return true;
|
|
11517
11469
|
}
|
|
11518
11470
|
return false;
|
|
11519
11471
|
}
|
|
11520
11472
|
function extractCompetitorsFromResponse(ctx) {
|
|
11521
11473
|
const competitors2 = /* @__PURE__ */ new Set();
|
|
11522
|
-
const
|
|
11523
|
-
const targetDomain = extractHostname2(ctx.targetDomain);
|
|
11474
|
+
const targetDomain = hostOf(ctx.targetDomain) ?? ctx.targetDomain;
|
|
11524
11475
|
for (const hint of ctx.manualCompetitors) {
|
|
11525
11476
|
if (isDomainLike(hint)) {
|
|
11526
|
-
const normalizedHint =
|
|
11527
|
-
if (
|
|
11528
|
-
if (ctx.citedDomains.some((domain) =>
|
|
11477
|
+
const normalizedHint = hostOf(hint) ?? hint;
|
|
11478
|
+
if (hostMatchesDomain(normalizedHint, targetDomain)) continue;
|
|
11479
|
+
if (ctx.citedDomains.some((domain) => hostMatchesDomain(domain, normalizedHint)) || textContainsDomain(ctx.answerText, normalizedHint)) {
|
|
11529
11480
|
competitors2.add(normalizedHint);
|
|
11530
11481
|
}
|
|
11531
11482
|
continue;
|
|
11532
11483
|
}
|
|
11533
|
-
if (hint.length >= 3 &&
|
|
11484
|
+
if (hint.length >= 3 && textContainsBrandAlias(ctx.answerText, hint)) {
|
|
11534
11485
|
competitors2.add(hint);
|
|
11535
11486
|
}
|
|
11536
11487
|
}
|
|
@@ -11579,27 +11530,8 @@ function uniqueStrings(values) {
|
|
|
11579
11530
|
values.filter((value) => typeof value === "string").map((value) => value.trim()).filter(Boolean)
|
|
11580
11531
|
)];
|
|
11581
11532
|
}
|
|
11582
|
-
function normalizeDomain(value) {
|
|
11583
|
-
const trimmed = value.trim();
|
|
11584
|
-
if (!trimmed) return trimmed;
|
|
11585
|
-
try {
|
|
11586
|
-
const url = trimmed.includes("://") ? new URL(trimmed) : new URL(`https://${trimmed}`);
|
|
11587
|
-
return url.hostname.replace(/^www\./, "").toLowerCase();
|
|
11588
|
-
} catch {
|
|
11589
|
-
return trimmed.replace(/^https?:\/\//, "").replace(/\/.*$/, "").replace(/^www\./, "").toLowerCase();
|
|
11590
|
-
}
|
|
11591
|
-
}
|
|
11592
|
-
function extractHostname2(value) {
|
|
11593
|
-
return normalizeDomain(value);
|
|
11594
|
-
}
|
|
11595
|
-
function domainMatches(candidate, target) {
|
|
11596
|
-
const normalizedCandidate = normalizeDomain(candidate);
|
|
11597
|
-
const normalizedTarget = normalizeDomain(target);
|
|
11598
|
-
return normalizedCandidate === normalizedTarget || normalizedCandidate.endsWith(`.${normalizedTarget}`);
|
|
11599
|
-
}
|
|
11600
11533
|
function isDomainLike(value) {
|
|
11601
|
-
|
|
11602
|
-
return normalized.includes(".") && !normalized.includes(" ");
|
|
11534
|
+
return registrableDomain(value).length > 0;
|
|
11603
11535
|
}
|
|
11604
11536
|
function clipText(value, length) {
|
|
11605
11537
|
if (value.length <= length) return value;
|
|
@@ -42,7 +42,7 @@ import {
|
|
|
42
42
|
trafficConnectWordpressRequestSchema,
|
|
43
43
|
trafficEventKindSchema,
|
|
44
44
|
trafficSeriesGranularitySchema
|
|
45
|
-
} from "./chunk-
|
|
45
|
+
} from "./chunk-GGIRLRAY.js";
|
|
46
46
|
|
|
47
47
|
// src/config.ts
|
|
48
48
|
import fs from "fs";
|
|
@@ -1087,6 +1087,22 @@ var createClient = (config = {}) => {
|
|
|
1087
1087
|
var client = createClient(createConfig());
|
|
1088
1088
|
|
|
1089
1089
|
// ../api-client-generated/src/generated/sdk.gen.ts
|
|
1090
|
+
var postApiV1ProjectsByNameGoogleGscSitemapsSubmit = (options) => {
|
|
1091
|
+
return (options.client ?? client).post({
|
|
1092
|
+
security: [
|
|
1093
|
+
{
|
|
1094
|
+
scheme: "bearer",
|
|
1095
|
+
type: "http"
|
|
1096
|
+
}
|
|
1097
|
+
],
|
|
1098
|
+
url: "/api/v1/projects/{name}/google/gsc/sitemaps/submit",
|
|
1099
|
+
...options,
|
|
1100
|
+
headers: {
|
|
1101
|
+
"Content-Type": "application/json",
|
|
1102
|
+
...options.headers
|
|
1103
|
+
}
|
|
1104
|
+
});
|
|
1105
|
+
};
|
|
1090
1106
|
var deleteApiV1ProjectsByName = (options) => {
|
|
1091
1107
|
return (options.client ?? client).delete({
|
|
1092
1108
|
security: [
|
|
@@ -5181,9 +5197,22 @@ var ApiClient = class {
|
|
|
5181
5197
|
})
|
|
5182
5198
|
);
|
|
5183
5199
|
}
|
|
5184
|
-
async gscSitemaps(project) {
|
|
5200
|
+
async gscSitemaps(project, params) {
|
|
5201
|
+
return this.invoke(
|
|
5202
|
+
() => getApiV1ProjectsByNameGoogleGscSitemaps({
|
|
5203
|
+
client: this.heyClient,
|
|
5204
|
+
path: { name: project },
|
|
5205
|
+
query: { sitemapIndex: params?.sitemapIndex }
|
|
5206
|
+
})
|
|
5207
|
+
);
|
|
5208
|
+
}
|
|
5209
|
+
async gscSubmitSitemaps(project, body) {
|
|
5185
5210
|
return this.invoke(
|
|
5186
|
-
() =>
|
|
5211
|
+
() => postApiV1ProjectsByNameGoogleGscSitemapsSubmit({
|
|
5212
|
+
client: this.heyClient,
|
|
5213
|
+
path: { name: project },
|
|
5214
|
+
body
|
|
5215
|
+
})
|
|
5187
5216
|
);
|
|
5188
5217
|
}
|
|
5189
5218
|
async gscDiscoverSitemaps(project) {
|
|
@@ -6149,6 +6178,92 @@ var gscCoverageHistoryInputSchema = z2.object({
|
|
|
6149
6178
|
project: projectNameSchema,
|
|
6150
6179
|
limit: z2.number().int().positive().max(500).optional()
|
|
6151
6180
|
});
|
|
6181
|
+
var gscSitemapsInputSchema = z2.object({
|
|
6182
|
+
project: projectNameSchema,
|
|
6183
|
+
sitemapIndex: z2.string().url().optional()
|
|
6184
|
+
});
|
|
6185
|
+
var gscSitemapsSubmitInputSchema = z2.union([
|
|
6186
|
+
z2.object({
|
|
6187
|
+
project: projectNameSchema,
|
|
6188
|
+
sitemapUrls: z2.array(z2.string().url()).min(1).max(50)
|
|
6189
|
+
}).strict(),
|
|
6190
|
+
z2.object({
|
|
6191
|
+
project: projectNameSchema,
|
|
6192
|
+
mode: z2.enum(["indexes", "all-files"])
|
|
6193
|
+
}).strict()
|
|
6194
|
+
]);
|
|
6195
|
+
async function submitGscSitemapsFromMcp(client2, input) {
|
|
6196
|
+
let sitemapUrls;
|
|
6197
|
+
if ("sitemapUrls" in input) {
|
|
6198
|
+
sitemapUrls = uniqueStrings(input.sitemapUrls);
|
|
6199
|
+
} else {
|
|
6200
|
+
const topLevel = await client2.gscSitemaps(input.project);
|
|
6201
|
+
if (input.mode === "indexes") {
|
|
6202
|
+
sitemapUrls = uniqueStrings(
|
|
6203
|
+
topLevel.preferredSubmissionUrls.length > 0 ? topLevel.preferredSubmissionUrls : topLevel.sitemaps.map((sitemap) => sitemap.path)
|
|
6204
|
+
);
|
|
6205
|
+
} else {
|
|
6206
|
+
const indexes = topLevel.sitemaps.filter((sitemap) => sitemap.isSitemapsIndex).map((sitemap) => sitemap.path);
|
|
6207
|
+
const expandedIndexUrls = [];
|
|
6208
|
+
for (let offset = 0; offset < indexes.length; offset += 4) {
|
|
6209
|
+
const children = await Promise.all(
|
|
6210
|
+
indexes.slice(offset, offset + 4).map(
|
|
6211
|
+
(sitemapIndex) => client2.gscSitemaps(input.project, { sitemapIndex })
|
|
6212
|
+
)
|
|
6213
|
+
);
|
|
6214
|
+
children.forEach((result, index) => {
|
|
6215
|
+
const sitemapIndex = indexes[offset + index];
|
|
6216
|
+
expandedIndexUrls.push(...result.sitemaps.length > 0 ? result.sitemaps.map((sitemap) => sitemap.path) : [sitemapIndex]);
|
|
6217
|
+
});
|
|
6218
|
+
}
|
|
6219
|
+
sitemapUrls = uniqueStrings([
|
|
6220
|
+
...topLevel.sitemaps.filter((sitemap) => !sitemap.isSitemapsIndex).map((sitemap) => sitemap.path),
|
|
6221
|
+
...expandedIndexUrls
|
|
6222
|
+
]);
|
|
6223
|
+
}
|
|
6224
|
+
}
|
|
6225
|
+
if (sitemapUrls.length === 0) {
|
|
6226
|
+
throw new Error("No GSC sitemaps found. Submit an explicit sitemap URL first.");
|
|
6227
|
+
}
|
|
6228
|
+
const aggregate = {
|
|
6229
|
+
summary: { total: 0, accepted: 0, failed: 0 },
|
|
6230
|
+
results: []
|
|
6231
|
+
};
|
|
6232
|
+
for (let offset = 0; offset < sitemapUrls.length; offset += 50) {
|
|
6233
|
+
const batchSitemapUrls = sitemapUrls.slice(offset, offset + 50);
|
|
6234
|
+
try {
|
|
6235
|
+
const result = await client2.gscSubmitSitemaps(input.project, {
|
|
6236
|
+
sitemapUrls: batchSitemapUrls
|
|
6237
|
+
});
|
|
6238
|
+
aggregate.summary.total += result.summary.total;
|
|
6239
|
+
aggregate.summary.accepted += result.summary.accepted;
|
|
6240
|
+
aggregate.summary.failed += result.summary.failed;
|
|
6241
|
+
aggregate.results.push(...result.results);
|
|
6242
|
+
} catch (cause) {
|
|
6243
|
+
if (offset === 0) throw cause;
|
|
6244
|
+
const attempted = aggregate.summary.total + batchSitemapUrls.length;
|
|
6245
|
+
const remaining = sitemapUrls.length - attempted;
|
|
6246
|
+
throw new CliError({
|
|
6247
|
+
code: "GOOGLE_SITEMAP_SUBMISSION_PARTIAL",
|
|
6248
|
+
message: `Sitemap submission stopped after ${aggregate.summary.total} completed results; ${batchSitemapUrls.length} are unconfirmed and ${remaining} were not attempted.`,
|
|
6249
|
+
exitCode: cause instanceof CliError && cause.exitCode === 1 ? 1 : EXIT_SYSTEM_ERROR,
|
|
6250
|
+
details: {
|
|
6251
|
+
project: input.project,
|
|
6252
|
+
accepted: aggregate.summary.accepted,
|
|
6253
|
+
failed: aggregate.summary.failed,
|
|
6254
|
+
completed: aggregate.summary.total,
|
|
6255
|
+
attempted,
|
|
6256
|
+
unconfirmed: batchSitemapUrls.length,
|
|
6257
|
+
remaining,
|
|
6258
|
+
unconfirmedBatch: { index: Math.floor(offset / 50) + 1, sitemapUrls: batchSitemapUrls },
|
|
6259
|
+
partialResult: aggregate,
|
|
6260
|
+
cause: cause instanceof CliError ? { code: cause.code, message: cause.message, details: cause.details } : { message: cause instanceof Error ? cause.message : String(cause) }
|
|
6261
|
+
}
|
|
6262
|
+
});
|
|
6263
|
+
}
|
|
6264
|
+
}
|
|
6265
|
+
return aggregate;
|
|
6266
|
+
}
|
|
6152
6267
|
var gaWindowInputSchema = z2.object({
|
|
6153
6268
|
project: projectNameSchema,
|
|
6154
6269
|
window: analyticsWindowSchema.optional()
|
|
@@ -6486,7 +6601,7 @@ var canonryMcpTools = [
|
|
|
6486
6601
|
description: "Get a Canonry project by name.",
|
|
6487
6602
|
access: "read",
|
|
6488
6603
|
tier: "core",
|
|
6489
|
-
inputSchema:
|
|
6604
|
+
inputSchema: gscSitemapsInputSchema,
|
|
6490
6605
|
annotations: readAnnotations(),
|
|
6491
6606
|
openApiOperations: ["GET /api/v1/projects/{name}"],
|
|
6492
6607
|
handler: (client2, input) => client2.getProject(input.project)
|
|
@@ -7048,10 +7163,21 @@ var canonryMcpTools = [
|
|
|
7048
7163
|
description: "Get sitemap data from Google Search Console for a Canonry project.",
|
|
7049
7164
|
access: "read",
|
|
7050
7165
|
tier: "gsc",
|
|
7051
|
-
inputSchema:
|
|
7166
|
+
inputSchema: gscSitemapsInputSchema,
|
|
7052
7167
|
annotations: readAnnotations(true),
|
|
7053
7168
|
openApiOperations: ["GET /api/v1/projects/{name}/google/gsc/sitemaps"],
|
|
7054
|
-
handler: (client2, input) => client2.gscSitemaps(input.project)
|
|
7169
|
+
handler: (client2, input) => client2.gscSitemaps(input.project, { sitemapIndex: input.sitemapIndex })
|
|
7170
|
+
}),
|
|
7171
|
+
defineTool({
|
|
7172
|
+
name: "canonry_gsc_sitemaps_submit",
|
|
7173
|
+
title: "Submit GSC sitemaps",
|
|
7174
|
+
description: "Submit up to 50 explicit sitemap URLs, preferred sitemap indexes, or every standalone top-level file plus index child to Google Search Console for refetching. Parent indexes are not redundantly submitted in all-files mode. Google acceptance does not guarantee indexing.",
|
|
7175
|
+
access: "write",
|
|
7176
|
+
tier: "gsc",
|
|
7177
|
+
inputSchema: gscSitemapsSubmitInputSchema,
|
|
7178
|
+
annotations: writeAnnotations({ idempotentHint: false, openWorldHint: true }),
|
|
7179
|
+
openApiOperations: ["POST /api/v1/projects/{name}/google/gsc/sitemaps/submit"],
|
|
7180
|
+
handler: submitGscSitemapsFromMcp
|
|
7055
7181
|
}),
|
|
7056
7182
|
defineTool({
|
|
7057
7183
|
name: "canonry_ga_status",
|