@canonry/canonry 7.9.1 → 7.11.0
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/aero/references/reporting.md +2 -0
- package/assets/agent-workspace/skills/canonry/references/aeo-analysis.md +1 -1
- package/assets/agent-workspace/skills/canonry/references/canonry-cli.md +30 -4
- package/assets/assets/{AuditHistoryPanel-D0nukTwD.js → AuditHistoryPanel-D1WdkJKU.js} +1 -1
- package/assets/assets/{BacklinksPage-B525ij0g.js → BacklinksPage-Uf1djxaV.js} +1 -1
- package/assets/assets/{HistoryPage-DvupqQDM.js → HistoryPage-CZPxzlS_.js} +1 -1
- package/assets/assets/{MeasurementPropertyPage-CwDbi1XN.js → MeasurementPropertyPage-CaWq1f2G.js} +1 -1
- package/assets/assets/{ProjectPage-DmZZ2C7q.js → ProjectPage-BimakE9X.js} +7 -7
- package/assets/assets/{RunsPage-DHTvHcGm.js → RunsPage-CDX5RxHi.js} +1 -1
- package/assets/assets/{SettingsPage-BwAFzB7A.js → SettingsPage-BfzKP-IR.js} +1 -1
- package/assets/assets/SiteHealthSection-42_E1ueq.js +4 -0
- package/assets/assets/{TrafficPage-BOcXASAM.js → TrafficPage-RjkpfGMw.js} +1 -1
- package/assets/assets/{TrafficSourceDetailPage-DTq0cN6g.js → TrafficSourceDetailPage-DIWDPo-8.js} +1 -1
- package/assets/assets/{extract-error-message-BOTDI6g5.js → extract-error-message-D_e8B2s_.js} +1 -1
- package/assets/assets/index-BNeiohKS.css +1 -0
- package/assets/assets/{index-BLJfGYUw.js → index-DKl_jsi3.js} +24 -24
- package/assets/assets/{react-sigma_core.esm.min-BEBdJNtD.js → react-sigma_core.esm.min-Br-N5hoB.js} +1 -1
- package/assets/assets/{v2-overview-adapter-BPZ-H3VY.js → v2-overview-adapter-BCSXgy2l.js} +1 -1
- package/assets/index.html +2 -2
- package/dist/{chunk-ZLB7WX5D.js → chunk-7G7YVTDA.js} +56 -6
- package/dist/{chunk-DO7XPDG5.js → chunk-CF7G2HGX.js} +5790 -4451
- package/dist/{chunk-LO56QXPO.js → chunk-GQAESNJT.js} +90 -2
- package/dist/{chunk-KRFTA4I7.js → chunk-HA2BAJ6Z.js} +3507 -2290
- package/dist/{chunk-AAMKTL6B.js → chunk-JRBQFRNT.js} +3 -3
- package/dist/{chunk-T2V2PESH.js → chunk-OH7E7TJD.js} +2 -2
- package/dist/{chunk-4BKRZGLC.js → chunk-S46DWUNR.js} +706 -245
- package/dist/cli.js +166 -38
- package/dist/{demo-server-KDMG3APY.js → demo-server-BYLZFDKI.js} +4 -4
- package/dist/index.js +6 -6
- package/dist/{intelligence-service-LAXJFE3U.js → intelligence-service-TIM4XTYH.js} +2 -2
- package/dist/mcp.js +4 -4
- package/package.json +10 -10
- package/assets/assets/SiteHealthSection-hi54eSIt.js +0 -4
- package/assets/assets/index-Rcbm8bK1.css +0 -1
package/dist/cli.js
CHANGED
|
@@ -25,6 +25,7 @@ import {
|
|
|
25
25
|
reparseStoredResult3,
|
|
26
26
|
reparseStoredResult4,
|
|
27
27
|
reparseStoredResult5,
|
|
28
|
+
resolveStoredApiResponse,
|
|
28
29
|
setGoogleAuthConfig,
|
|
29
30
|
setTelemetryPreference,
|
|
30
31
|
setTelemetrySource,
|
|
@@ -32,11 +33,11 @@ import {
|
|
|
32
33
|
trackCliCommandFinished,
|
|
33
34
|
trackEvent,
|
|
34
35
|
waitForServerRuntimeStartup
|
|
35
|
-
} from "./chunk-
|
|
36
|
+
} from "./chunk-S46DWUNR.js";
|
|
36
37
|
import {
|
|
37
38
|
autoSyncSkills,
|
|
38
39
|
formatAutoSyncNotice
|
|
39
|
-
} from "./chunk-
|
|
40
|
+
} from "./chunk-JRBQFRNT.js";
|
|
40
41
|
import {
|
|
41
42
|
configExists,
|
|
42
43
|
createApiClient,
|
|
@@ -53,13 +54,13 @@ import {
|
|
|
53
54
|
saveConfig,
|
|
54
55
|
saveConfigPatch,
|
|
55
56
|
shouldPrintServeSkillsNudge
|
|
56
|
-
} from "./chunk-
|
|
57
|
+
} from "./chunk-GQAESNJT.js";
|
|
57
58
|
import {
|
|
58
59
|
DEFAULT_DEMO_TRUSTED_PROXIES,
|
|
59
60
|
trustedProxiesProblem,
|
|
60
61
|
trustedProxyProblem
|
|
61
62
|
} from "./chunk-RB2F4D3Z.js";
|
|
62
|
-
import "./chunk-
|
|
63
|
+
import "./chunk-OH7E7TJD.js";
|
|
63
64
|
import {
|
|
64
65
|
CliError,
|
|
65
66
|
EXIT_SYSTEM_ERROR,
|
|
@@ -71,7 +72,7 @@ import {
|
|
|
71
72
|
runMeasurementDraftAction,
|
|
72
73
|
systemError,
|
|
73
74
|
usageError
|
|
74
|
-
} from "./chunk-
|
|
75
|
+
} from "./chunk-7G7YVTDA.js";
|
|
75
76
|
import {
|
|
76
77
|
CLOUDFLARE_WORKER_BINDINGS,
|
|
77
78
|
CLOUDFLARE_WORKER_GENERATED_MARKER,
|
|
@@ -83,6 +84,7 @@ import {
|
|
|
83
84
|
backfillProjectAnswerMentions,
|
|
84
85
|
classifyAiUserFetch,
|
|
85
86
|
classifyCrawler,
|
|
87
|
+
competitorIdentityColumns,
|
|
86
88
|
competitors,
|
|
87
89
|
crawlerEventsHourly,
|
|
88
90
|
createClient,
|
|
@@ -99,8 +101,9 @@ import {
|
|
|
99
101
|
queries,
|
|
100
102
|
querySnapshots,
|
|
101
103
|
rawEventSamples,
|
|
104
|
+
readMarketCompetitorNames,
|
|
102
105
|
runs
|
|
103
|
-
} from "./chunk-
|
|
106
|
+
} from "./chunk-HA2BAJ6Z.js";
|
|
104
107
|
import {
|
|
105
108
|
AdsDeliverySnapshotStatuses,
|
|
106
109
|
AdsHistoricalCampaignRollupStatuses,
|
|
@@ -155,6 +158,7 @@ import {
|
|
|
155
158
|
buildModelChangeNotice,
|
|
156
159
|
canonicalizeGtmAccountId,
|
|
157
160
|
canonicalizeGtmResourceSelection,
|
|
161
|
+
competitorAutoAliasModeSchema,
|
|
158
162
|
competitorLandscapeQuerySchema,
|
|
159
163
|
computeCompetitorOverlap,
|
|
160
164
|
contentTargetDismissRequestSchema,
|
|
@@ -229,7 +233,7 @@ import {
|
|
|
229
233
|
visibilityCompareSelectionSchema,
|
|
230
234
|
visibilityReportRequestSchema,
|
|
231
235
|
winnabilityClassSchema
|
|
232
|
-
} from "./chunk-
|
|
236
|
+
} from "./chunk-CF7G2HGX.js";
|
|
233
237
|
|
|
234
238
|
// src/cli.ts
|
|
235
239
|
import { pathToFileURL } from "url";
|
|
@@ -779,7 +783,7 @@ function parseDemoTrustedProxies(values) {
|
|
|
779
783
|
async function demoCommand(options) {
|
|
780
784
|
const { host, port } = parseDemoListenOptions(options);
|
|
781
785
|
const trustProxy = parseDemoTrustedProxies(options.trustProxy);
|
|
782
|
-
const { createDemoServer } = await import("./demo-server-
|
|
786
|
+
const { createDemoServer } = await import("./demo-server-BYLZFDKI.js");
|
|
783
787
|
const app = await createDemoServer({ trustProxy });
|
|
784
788
|
let stopping = false;
|
|
785
789
|
const stop = () => {
|
|
@@ -857,7 +861,7 @@ async function backfillAnswerVisibilityCommand(opts) {
|
|
|
857
861
|
else runIdsByProject.set(run.projectId, [run.id]);
|
|
858
862
|
}
|
|
859
863
|
for (const project2 of scopedProjects) {
|
|
860
|
-
const competitorsForRun = createRunCompetitorResolver(db, db.select(
|
|
864
|
+
const competitorsForRun = createRunCompetitorResolver(db, db.select(competitorIdentityColumns).from(competitors).where(eq(competitors.projectId, project2.id)).orderBy(competitors.domain).all(), readMarketCompetitorNames(db, project2.id));
|
|
861
865
|
const runIds = runIdsByProject.get(project2.id) ?? [];
|
|
862
866
|
if (runIds.length === 0) continue;
|
|
863
867
|
const projectDomains = effectiveDomains({
|
|
@@ -1193,7 +1197,7 @@ No DB writes performed. Re-run without --dry-run to apply.`);
|
|
|
1193
1197
|
}
|
|
1194
1198
|
}
|
|
1195
1199
|
async function backfillInsightsCommand(project2, opts) {
|
|
1196
|
-
const { IntelligenceService } = await import("./intelligence-service-
|
|
1200
|
+
const { IntelligenceService } = await import("./intelligence-service-TIM4XTYH.js");
|
|
1197
1201
|
const config = loadConfig();
|
|
1198
1202
|
const db = createClient(config.database);
|
|
1199
1203
|
migrate(db);
|
|
@@ -1509,19 +1513,6 @@ function reparseProviderSnapshot(provider, rawResponse) {
|
|
|
1509
1513
|
return null;
|
|
1510
1514
|
}
|
|
1511
1515
|
}
|
|
1512
|
-
function resolveStoredApiResponse(parsed) {
|
|
1513
|
-
const nested = parsed.apiResponse;
|
|
1514
|
-
if (nested !== null && typeof nested === "object" && !Array.isArray(nested)) {
|
|
1515
|
-
return nested;
|
|
1516
|
-
}
|
|
1517
|
-
if (looksLikeProviderApiResponse(parsed)) {
|
|
1518
|
-
return parsed;
|
|
1519
|
-
}
|
|
1520
|
-
return null;
|
|
1521
|
-
}
|
|
1522
|
-
function looksLikeProviderApiResponse(value) {
|
|
1523
|
-
return Array.isArray(value.output) || Array.isArray(value.content) || Array.isArray(value.candidates) || Array.isArray(value.choices);
|
|
1524
|
-
}
|
|
1525
1516
|
function stringifyStoredSnapshotEnvelope(rawResponse, reparsed) {
|
|
1526
1517
|
const parsed = parseJsonColumn(rawResponse, {});
|
|
1527
1518
|
const apiResponse = resolveStoredApiResponse(parsed);
|
|
@@ -5614,7 +5605,7 @@ async function gaAiReferralDaily(project2, opts) {
|
|
|
5614
5605
|
console.log(JSON.stringify(result, null, 2));
|
|
5615
5606
|
return;
|
|
5616
5607
|
} else if (opts?.format === "jsonl") {
|
|
5617
|
-
emitJsonl(result.days.map((
|
|
5608
|
+
emitJsonl(result.days.map((day2) => ({ project: project2, window: opts?.window, startDate: opts?.startDate, endDate: opts?.endDate, ...day2 })));
|
|
5618
5609
|
return;
|
|
5619
5610
|
}
|
|
5620
5611
|
if (result.days.length === 0) {
|
|
@@ -5627,10 +5618,10 @@ async function gaAiReferralDaily(project2, opts) {
|
|
|
5627
5618
|
`);
|
|
5628
5619
|
console.log(` ${"DATE".padEnd(dateWidth)} ${"SOURCE".padEnd(sourceWidth)} ${"SESSIONS".padEnd(10)}${"PAID".padEnd(8)}${"ORGANIC".padEnd(9)}`);
|
|
5629
5620
|
console.log(` ${"\u2500".repeat(dateWidth)} ${"\u2500".repeat(sourceWidth)} ${"\u2500".repeat(10)}${"\u2500".repeat(8)}${"\u2500".repeat(9)}`);
|
|
5630
|
-
for (const
|
|
5631
|
-
for (const entry of
|
|
5621
|
+
for (const day2 of result.days) {
|
|
5622
|
+
for (const entry of day2.bySource) {
|
|
5632
5623
|
console.log(
|
|
5633
|
-
` ${
|
|
5624
|
+
` ${day2.date.padEnd(dateWidth)} ${entry.source.padEnd(sourceWidth)} ${String(entry.sessions).padEnd(10)}${String(entry.paidSessions).padEnd(8)}${String(entry.organicSessions).padEnd(9)}`
|
|
5634
5625
|
);
|
|
5635
5626
|
}
|
|
5636
5627
|
}
|
|
@@ -9139,7 +9130,11 @@ function sameAliasName(a, b) {
|
|
|
9139
9130
|
async function competitorAliases(project2, domain, options) {
|
|
9140
9131
|
const client = getClient10();
|
|
9141
9132
|
let result;
|
|
9142
|
-
if (options.
|
|
9133
|
+
if (options.block !== void 0) {
|
|
9134
|
+
result = await client.blockCompetitorAliases(project2, domain, options.block);
|
|
9135
|
+
} else if (options.unblock !== void 0) {
|
|
9136
|
+
result = await client.unblockCompetitorAliases(project2, domain, options.unblock);
|
|
9137
|
+
} else if (options.set !== void 0 || options.clear === true) {
|
|
9143
9138
|
result = await client.setCompetitorAliases(project2, domain, options.clear ? [] : options.set ?? []);
|
|
9144
9139
|
} else {
|
|
9145
9140
|
const target = normalizeCompetitorDomain(domain.trim());
|
|
@@ -9161,7 +9156,12 @@ async function competitorAliases(project2, domain, options) {
|
|
|
9161
9156
|
throw new CliError({
|
|
9162
9157
|
code: "NOT_FOUND",
|
|
9163
9158
|
message: `Competitor "${target}" is not tracked by project "${project2}"`,
|
|
9164
|
-
displayMessage:
|
|
9159
|
+
displayMessage: [
|
|
9160
|
+
`Error: competitor "${target}" is not a project competitor of "${project2}".`,
|
|
9161
|
+
`If an Advanced market pins it, list its plan names and learned names with: canonry competitor aliases detect ${project2}`,
|
|
9162
|
+
`and block or unblock a learned name with: canonry competitor aliases ${project2} ${target} --block <name> (or --unblock <name>); change its plan names in a measurement draft.`,
|
|
9163
|
+
`To track it in every market instead (it then counts outside its markets): canonry competitor add ${project2} ${target}`
|
|
9164
|
+
].join("\n"),
|
|
9165
9165
|
details: { project: project2, domain: target }
|
|
9166
9166
|
});
|
|
9167
9167
|
}
|
|
@@ -9184,7 +9184,81 @@ async function competitorAliases(project2, domain, options) {
|
|
|
9184
9184
|
console.log(JSON.stringify(result, null, 2));
|
|
9185
9185
|
return;
|
|
9186
9186
|
}
|
|
9187
|
-
|
|
9187
|
+
printCompetitorNames(result);
|
|
9188
|
+
}
|
|
9189
|
+
function day(iso) {
|
|
9190
|
+
return iso.slice(0, 10);
|
|
9191
|
+
}
|
|
9192
|
+
function autoAliasEvidence(record) {
|
|
9193
|
+
const precision = record.precision === null ? "n/a" : formatPercent(record.precision, RatioUnits.fraction);
|
|
9194
|
+
const lift = record.lift === void 0 || record.lift === null ? "" : ` (${record.lift}x the rate in answers that do not name it)`;
|
|
9195
|
+
const cased = record.nameCasedAnswers === void 0 ? "" : `; written as a name in ${record.nameCasedAnswers}`;
|
|
9196
|
+
const seen = record.firstSeen ? `; seen ${day(record.firstSeen)} to ${day(record.lastSeen)}` : "";
|
|
9197
|
+
return `paired in ${record.directPairs} answers over ${record.runs} sweeps; ${precision} of ${record.namingAnswers} answers naming it cite the site${lift}${cased}; co-occurs in ${record.cooccurrences}${seen}`;
|
|
9198
|
+
}
|
|
9199
|
+
function printCompetitorNames(competitor) {
|
|
9200
|
+
const auto = competitor.autoAliases ?? [];
|
|
9201
|
+
const blocked = competitor.blockedAliases ?? [];
|
|
9202
|
+
if (competitor.marketKeys) {
|
|
9203
|
+
console.log(`Plan names for ${competitor.domain} (Advanced markets: ${competitor.marketKeys.join(", ")}): ${formatAliases(storedAliases(competitor))}`);
|
|
9204
|
+
} else {
|
|
9205
|
+
console.log(`Aliases for ${competitor.domain}: ${formatAliases(storedAliases(competitor))}`);
|
|
9206
|
+
}
|
|
9207
|
+
if (auto.length === 0) {
|
|
9208
|
+
console.log("Auto-detected from stored answers: (none)");
|
|
9209
|
+
} else {
|
|
9210
|
+
console.log("Auto-detected from stored answers:");
|
|
9211
|
+
for (const record of auto) console.log(` ${record.name} (${autoAliasEvidence(record)})`);
|
|
9212
|
+
}
|
|
9213
|
+
console.log(`Blocked from auto-detection: ${formatAliases(blocked)}`);
|
|
9214
|
+
}
|
|
9215
|
+
var CANDIDATE_MARKS = {
|
|
9216
|
+
added: "+",
|
|
9217
|
+
kept: "=",
|
|
9218
|
+
removed: "-",
|
|
9219
|
+
review: "?",
|
|
9220
|
+
rejected: "x"
|
|
9221
|
+
};
|
|
9222
|
+
async function detectCompetitorAutoAliases(project2, options) {
|
|
9223
|
+
const client = getClient10();
|
|
9224
|
+
const result = options.apply ? await client.applyCompetitorAutoAliases(project2) : await client.previewCompetitorAutoAliases(project2);
|
|
9225
|
+
if (options.format === "json") {
|
|
9226
|
+
console.log(JSON.stringify(result, null, 2));
|
|
9227
|
+
return;
|
|
9228
|
+
}
|
|
9229
|
+
if (options.format === "jsonl") {
|
|
9230
|
+
emitJsonl(result.competitors.map((competitor) => ({ project: result.project, applied: result.applied, ...competitor })));
|
|
9231
|
+
return;
|
|
9232
|
+
}
|
|
9233
|
+
const { scan, thresholds } = result;
|
|
9234
|
+
console.log(`Competitor auto-alias detection for "${result.project}" (${result.applied ? "applied" : "dry run, nothing stored"})`);
|
|
9235
|
+
console.log(`Scanned ${scan.runs} runs, ${scan.snapshots} snapshots, ${scan.answers} answers (newest ${scan.maxRuns} runs, up to ${scan.maxSnapshots} snapshots; provider citations ${scan.providerCitations ? "read" : "unavailable, answer-text pairings only"})`);
|
|
9236
|
+
console.log(`Applies a name paired with the site in ${thresholds.minDirectPairs}+ answers over ${thresholds.minRuns}+ sweeps, named in ${thresholds.minNamingAnswers}+ answers, precision ${formatPercent(thresholds.minPrecision, RatioUnits.fraction)}+, cited ${thresholds.minLift}x+ more often when named than otherwise, written as a name in ${formatPercent(thresholds.minNameCasedShare, RatioUnits.fraction)}+ of them, ${thresholds.dominanceMultiple}x any other competitor's pairings, ${thresholds.minKeyLength}+ letters or digits, and visibly tied to the domain`);
|
|
9237
|
+
console.log("Legend: + added = kept - removed ? review only x rejected");
|
|
9238
|
+
if (result.competitors.length === 0) {
|
|
9239
|
+
console.log(`
|
|
9240
|
+
No competitors tracked for "${result.project}".`);
|
|
9241
|
+
return;
|
|
9242
|
+
}
|
|
9243
|
+
for (const competitor of result.competitors) {
|
|
9244
|
+
console.log(competitor.marketKeys ? `
|
|
9245
|
+
${competitor.domain} (Advanced markets: ${competitor.marketKeys.join(", ")})` : `
|
|
9246
|
+
${competitor.domain}`);
|
|
9247
|
+
if (competitor.aliases.length) console.log(` ${competitor.marketKeys ? "plan names" : "curated"}: ${competitor.aliases.join(", ")}`);
|
|
9248
|
+
if (competitor.blockedAliases.length) console.log(` blocked: ${competitor.blockedAliases.join(", ")}`);
|
|
9249
|
+
if (competitor.candidates.length === 0) {
|
|
9250
|
+
console.log(" (no candidate names paired with this site)");
|
|
9251
|
+
continue;
|
|
9252
|
+
}
|
|
9253
|
+
for (const candidate of competitor.candidates) {
|
|
9254
|
+
const reason = candidate.reason ? ` [${candidate.reason}${candidate.conflictsWith ? `: ${candidate.conflictsWith}` : ""}]` : "";
|
|
9255
|
+
console.log(` ${CANDIDATE_MARKS[candidate.status]} ${candidate.name}${reason} (${autoAliasEvidence(candidate)})`);
|
|
9256
|
+
}
|
|
9257
|
+
}
|
|
9258
|
+
if (!result.applied && result.changed) {
|
|
9259
|
+
console.log(`
|
|
9260
|
+
Run with --apply to store these changes now (the server also applies them after the next sweep).`);
|
|
9261
|
+
}
|
|
9188
9262
|
}
|
|
9189
9263
|
async function removeCompetitors(project2, domains, format) {
|
|
9190
9264
|
const client = getClient10();
|
|
@@ -9233,7 +9307,12 @@ async function listCompetitors(project2, format) {
|
|
|
9233
9307
|
`);
|
|
9234
9308
|
for (const c of comps) {
|
|
9235
9309
|
const aliases = storedAliases(c);
|
|
9236
|
-
|
|
9310
|
+
const auto = (c.autoAliases ?? []).map((record) => record.name);
|
|
9311
|
+
const names = [
|
|
9312
|
+
...aliases.length > 0 ? [`aliases: ${aliases.join(", ")}`] : [],
|
|
9313
|
+
...auto.length > 0 ? [`auto: ${auto.join(", ")}`] : []
|
|
9314
|
+
];
|
|
9315
|
+
console.log(names.length > 0 ? ` ${c.domain} (${names.join("; ")})` : ` ${c.domain}`);
|
|
9237
9316
|
}
|
|
9238
9317
|
}
|
|
9239
9318
|
async function showCompetitorLandscape(project2, options) {
|
|
@@ -9325,7 +9404,8 @@ function printLandscapeRows(heading, rows, showSampleCount = false, context, que
|
|
|
9325
9404
|
|
|
9326
9405
|
// src/cli-commands/competitor.ts
|
|
9327
9406
|
var ADD_USAGE = "canonry competitor add <project> <domain...> [--alias <name>]... [--format json]";
|
|
9328
|
-
var ALIASES_USAGE = "canonry competitor aliases <project> <domain> [--set <name>]... [--add <name>]... [--remove <name>]... [--clear] [--format json]";
|
|
9407
|
+
var ALIASES_USAGE = "canonry competitor aliases <project> <domain> [--set <name>]... [--add <name>]... [--remove <name>]... [--clear] [--block <name>]... [--unblock <name>]... [--format json]";
|
|
9408
|
+
var DETECT_USAGE = "canonry competitor aliases detect <project> [--apply] [--format json|jsonl]";
|
|
9329
9409
|
var LANDSCAPE_USAGE = "canonry competitor landscape <project> [--window 7d|30d|90d|all] [--group-key <key>|--scope all-markets] [--by-model] [--provider <provider> [--model <id>]] [--query-class all|branded|non-brand] [--answers all|not-mentioned] [--location <label>] [--run-id <id>] [--format json|jsonl]";
|
|
9330
9410
|
function parseLandscapeScope(value) {
|
|
9331
9411
|
if (value === void 0 || value === "") return void 0;
|
|
@@ -9366,6 +9446,20 @@ Usage: ${ADD_USAGE}`, {
|
|
|
9366
9446
|
await addCompetitors(project2, domains, input.format, aliases);
|
|
9367
9447
|
}
|
|
9368
9448
|
},
|
|
9449
|
+
{
|
|
9450
|
+
// Longest path wins in dispatch, so `detect` is reserved as the first
|
|
9451
|
+
// positional: a project literally named "detect" reads its aliases with
|
|
9452
|
+
// `competitor list detect`.
|
|
9453
|
+
path: ["competitor", "aliases", "detect"],
|
|
9454
|
+
usage: DETECT_USAGE,
|
|
9455
|
+
options: {
|
|
9456
|
+
apply: { type: "boolean" }
|
|
9457
|
+
},
|
|
9458
|
+
run: async (input) => {
|
|
9459
|
+
const project2 = requireProject(input, "competitor.aliases.detect", DETECT_USAGE);
|
|
9460
|
+
await detectCompetitorAutoAliases(project2, { apply: getBoolean(input.values, "apply"), format: input.format });
|
|
9461
|
+
}
|
|
9462
|
+
},
|
|
9369
9463
|
{
|
|
9370
9464
|
path: ["competitor", "aliases"],
|
|
9371
9465
|
usage: ALIASES_USAGE,
|
|
@@ -9373,7 +9467,9 @@ Usage: ${ADD_USAGE}`, {
|
|
|
9373
9467
|
set: multiStringOption(),
|
|
9374
9468
|
add: multiStringOption(),
|
|
9375
9469
|
remove: multiStringOption(),
|
|
9376
|
-
clear: { type: "boolean" }
|
|
9470
|
+
clear: { type: "boolean" },
|
|
9471
|
+
block: multiStringOption(),
|
|
9472
|
+
unblock: multiStringOption()
|
|
9377
9473
|
},
|
|
9378
9474
|
run: async (input) => {
|
|
9379
9475
|
const project2 = requireProject(input, "competitor.aliases", ALIASES_USAGE);
|
|
@@ -9386,6 +9482,15 @@ Usage: ${ADD_USAGE}`, {
|
|
|
9386
9482
|
const add = getStringArray(input.values, "add");
|
|
9387
9483
|
const remove = getStringArray(input.values, "remove");
|
|
9388
9484
|
const clear = getBoolean(input.values, "clear");
|
|
9485
|
+
const block = getStringArray(input.values, "block");
|
|
9486
|
+
const unblock = getStringArray(input.values, "unblock");
|
|
9487
|
+
if ((block !== void 0 || unblock !== void 0) && (block !== void 0 && unblock !== void 0 || set !== void 0 || clear || add !== void 0 || remove !== void 0)) {
|
|
9488
|
+
throw usageError(`Error: --block and --unblock change answer-derived auto-detection only, so they cannot be combined with each other or with curated edits (--set, --add, --remove, --clear)
|
|
9489
|
+
Usage: ${ALIASES_USAGE}`, {
|
|
9490
|
+
message: "--block and --unblock cannot be combined with each other or with --set/--add/--remove/--clear",
|
|
9491
|
+
details: { command: "competitor.aliases", usage: ALIASES_USAGE }
|
|
9492
|
+
});
|
|
9493
|
+
}
|
|
9389
9494
|
const exclusive = [set !== void 0, clear].filter(Boolean).length;
|
|
9390
9495
|
if (exclusive > 1 || exclusive === 1 && (add !== void 0 || remove !== void 0)) {
|
|
9391
9496
|
throw usageError(`Error: --set and --clear replace the whole list, so they cannot be combined with each other or with --add/--remove
|
|
@@ -9394,7 +9499,7 @@ Usage: ${ALIASES_USAGE}`, {
|
|
|
9394
9499
|
details: { command: "competitor.aliases", usage: ALIASES_USAGE }
|
|
9395
9500
|
});
|
|
9396
9501
|
}
|
|
9397
|
-
await competitorAliases(project2, domain, { set, add, remove, clear, format: input.format });
|
|
9502
|
+
await competitorAliases(project2, domain, { set, add, remove, clear, block, unblock, format: input.format });
|
|
9398
9503
|
}
|
|
9399
9504
|
},
|
|
9400
9505
|
{
|
|
@@ -13685,12 +13790,20 @@ async function showProject(name, format) {
|
|
|
13685
13790
|
if (project2.siteAuditMaxPages !== void 0) {
|
|
13686
13791
|
console.log(` Site Health page budget: ${formatSiteAuditPageBudget(project2.siteAuditMaxPages)}`);
|
|
13687
13792
|
}
|
|
13793
|
+
if (project2.competitorAutoAliases !== void 0) {
|
|
13794
|
+
console.log(` Competitor auto aliases: ${formatCompetitorAutoAliasMode(project2.competitorAutoAliases)}`);
|
|
13795
|
+
}
|
|
13688
13796
|
console.log(` Tags: ${project2.tags.length > 0 ? project2.tags.join(", ") : "(none)"}`);
|
|
13689
13797
|
const labelEntries = Object.entries(project2.labels);
|
|
13690
13798
|
console.log(` Labels: ${labelEntries.length > 0 ? labelEntries.map(([k, v]) => `${k}=${v}`).join(", ") : "(none)"}`);
|
|
13691
13799
|
if (project2.createdAt) console.log(` Created: ${project2.createdAt}`);
|
|
13692
13800
|
if (project2.updatedAt) console.log(` Updated: ${project2.updatedAt}`);
|
|
13693
13801
|
}
|
|
13802
|
+
function formatCompetitorAutoAliasMode(mode) {
|
|
13803
|
+
if (mode === "apply") return "apply (names detected after each sweep are stored and counted)";
|
|
13804
|
+
if (mode === "off") return "off (no detection after sweeps)";
|
|
13805
|
+
return "preview (detected after each sweep and logged; nothing stored)";
|
|
13806
|
+
}
|
|
13694
13807
|
async function updateProjectSettings(name, opts) {
|
|
13695
13808
|
const client = getClient22();
|
|
13696
13809
|
const project2 = await client.getProject(name);
|
|
@@ -13771,7 +13884,9 @@ async function updateProjectSettings(name, opts) {
|
|
|
13771
13884
|
...opts.negativeReviewMaxStars !== void 0 ? { negativeReviewMaxStars: opts.negativeReviewMaxStars } : {},
|
|
13772
13885
|
// Same for the page budget: never echoed from the read above, so an edit
|
|
13773
13886
|
// that does not touch it cannot overwrite a newer one or send a stray null.
|
|
13774
|
-
...opts.siteAuditMaxPages !== void 0 ? { siteAuditMaxPages: opts.siteAuditMaxPages } : {}
|
|
13887
|
+
...opts.siteAuditMaxPages !== void 0 ? { siteAuditMaxPages: opts.siteAuditMaxPages } : {},
|
|
13888
|
+
// Same for the detection mode.
|
|
13889
|
+
...opts.competitorAutoAliases !== void 0 ? { competitorAutoAliases: opts.competitorAutoAliases } : {}
|
|
13775
13890
|
});
|
|
13776
13891
|
warnDroppedDispatchModes(touchesDispatch ? providerDispatchModes : project2.providerDispatchModes ?? {}, result);
|
|
13777
13892
|
if (isMachineFormat(opts.format)) {
|
|
@@ -13925,7 +14040,7 @@ var PROJECT_CLI_COMMANDS = [
|
|
|
13925
14040
|
},
|
|
13926
14041
|
{
|
|
13927
14042
|
path: ["project", "update"],
|
|
13928
|
-
usage: "canonry project update <name> [--domain <domain>] [--owned-domain <domain>...] [--add-domain <domain>...] [--remove-domain <domain>...] [--alias <name>...] [--add-alias <name>...] [--remove-alias <name>...] [--add-qualified-alias <name>...] [--remove-qualified-alias <name>...] [--country <code>] [--language <lang>] [--display-name <name>] [--provider <name>...] [--all-providers] [--provider-model provider=model...] [--clear-provider-model <provider>...] [--dispatch-mode provider=sync|batch...] [--clear-dispatch-mode <provider>...] [--negative-review-max-stars <1-4|default>] [--site-audit-max-pages <1-50000|full>] [--format json]",
|
|
14043
|
+
usage: "canonry project update <name> [--domain <domain>] [--owned-domain <domain>...] [--add-domain <domain>...] [--remove-domain <domain>...] [--alias <name>...] [--add-alias <name>...] [--remove-alias <name>...] [--add-qualified-alias <name>...] [--remove-qualified-alias <name>...] [--country <code>] [--language <lang>] [--display-name <name>] [--provider <name>...] [--all-providers] [--provider-model provider=model...] [--clear-provider-model <provider>...] [--dispatch-mode provider=sync|batch...] [--clear-dispatch-mode <provider>...] [--negative-review-max-stars <1-4|default>] [--site-audit-max-pages <1-50000|full>] [--competitor-auto-aliases <off|preview|apply>] [--format json]",
|
|
13929
14044
|
options: {
|
|
13930
14045
|
domain: { type: "string", short: "d" },
|
|
13931
14046
|
"owned-domain": multiStringOption(),
|
|
@@ -13946,13 +14061,14 @@ var PROJECT_CLI_COMMANDS = [
|
|
|
13946
14061
|
"dispatch-mode": multiStringOption(),
|
|
13947
14062
|
"clear-dispatch-mode": multiStringOption(),
|
|
13948
14063
|
"negative-review-max-stars": stringOption(),
|
|
13949
|
-
"site-audit-max-pages": stringOption()
|
|
14064
|
+
"site-audit-max-pages": stringOption(),
|
|
14065
|
+
"competitor-auto-aliases": stringOption()
|
|
13950
14066
|
},
|
|
13951
14067
|
run: async (input) => {
|
|
13952
14068
|
const name = requireProject(
|
|
13953
14069
|
input,
|
|
13954
14070
|
"project.update",
|
|
13955
|
-
"canonry project update <name> [--domain <domain>] [--owned-domain <domain>...] [--add-domain <domain>...] [--remove-domain <domain>...] [--alias <name>...] [--add-alias <name>...] [--remove-alias <name>...] [--add-qualified-alias <name>...] [--remove-qualified-alias <name>...] [--country <code>] [--language <lang>] [--display-name <name>] [--provider <name>...] [--all-providers] [--provider-model provider=model...] [--clear-provider-model <provider>...] [--dispatch-mode provider=sync|batch...] [--clear-dispatch-mode <provider>...] [--negative-review-max-stars <1-4|default>] [--site-audit-max-pages <1-50000|full>] [--format json]"
|
|
14071
|
+
"canonry project update <name> [--domain <domain>] [--owned-domain <domain>...] [--add-domain <domain>...] [--remove-domain <domain>...] [--alias <name>...] [--add-alias <name>...] [--remove-alias <name>...] [--add-qualified-alias <name>...] [--remove-qualified-alias <name>...] [--country <code>] [--language <lang>] [--display-name <name>] [--provider <name>...] [--all-providers] [--provider-model provider=model...] [--clear-provider-model <provider>...] [--dispatch-mode provider=sync|batch...] [--clear-dispatch-mode <provider>...] [--negative-review-max-stars <1-4|default>] [--site-audit-max-pages <1-50000|full>] [--competitor-auto-aliases <off|preview|apply>] [--format json]"
|
|
13956
14072
|
);
|
|
13957
14073
|
const providers = getStringArray(input.values, "provider");
|
|
13958
14074
|
const allProviders = getBoolean(input.values, "all-providers");
|
|
@@ -13987,6 +14103,7 @@ var PROJECT_CLI_COMMANDS = [
|
|
|
13987
14103
|
clearDispatchModes,
|
|
13988
14104
|
negativeReviewMaxStars: parseNegativeReviewMaxStars(getString(input.values, "negative-review-max-stars")),
|
|
13989
14105
|
siteAuditMaxPages: parseSiteAuditMaxPages(getString(input.values, "site-audit-max-pages"), "project.update"),
|
|
14106
|
+
competitorAutoAliases: parseCompetitorAutoAliasMode(getString(input.values, "competitor-auto-aliases")),
|
|
13990
14107
|
format: input.format
|
|
13991
14108
|
});
|
|
13992
14109
|
}
|
|
@@ -14151,6 +14268,17 @@ function parseSiteAuditMaxPages(raw, command) {
|
|
|
14151
14268
|
}
|
|
14152
14269
|
return parsed.data;
|
|
14153
14270
|
}
|
|
14271
|
+
function parseCompetitorAutoAliasMode(raw) {
|
|
14272
|
+
if (raw === void 0) return void 0;
|
|
14273
|
+
const parsed = competitorAutoAliasModeSchema.safeParse(raw.trim().toLowerCase());
|
|
14274
|
+
if (!parsed.success) {
|
|
14275
|
+
throw usageError("Error: --competitor-auto-aliases must be off, preview or apply", {
|
|
14276
|
+
message: "--competitor-auto-aliases must be off, preview or apply",
|
|
14277
|
+
details: { command: "project.update", option: "competitor-auto-aliases", value: raw }
|
|
14278
|
+
});
|
|
14279
|
+
}
|
|
14280
|
+
return parsed.data;
|
|
14281
|
+
}
|
|
14154
14282
|
|
|
14155
14283
|
// src/commands/organic-evidence.ts
|
|
14156
14284
|
async function showOrganicEvidence(project2, opts) {
|
|
@@ -5,11 +5,11 @@ import {
|
|
|
5
5
|
computeFactorAverages,
|
|
6
6
|
layoutSiteCrawlGraphInput,
|
|
7
7
|
persistSiteCrawlGraphLayout
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-OH7E7TJD.js";
|
|
9
9
|
import {
|
|
10
10
|
PACKAGE_VERSION,
|
|
11
11
|
canonryMcpTools
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-7G7YVTDA.js";
|
|
13
13
|
import {
|
|
14
14
|
HISTORY_WINDOW_RUNS,
|
|
15
15
|
IntelligenceService,
|
|
@@ -83,7 +83,7 @@ import {
|
|
|
83
83
|
siteCrawlPages,
|
|
84
84
|
siteCrawlSnapshots,
|
|
85
85
|
trafficSources
|
|
86
|
-
} from "./chunk-
|
|
86
|
+
} from "./chunk-HA2BAJ6Z.js";
|
|
87
87
|
import {
|
|
88
88
|
RunKinds,
|
|
89
89
|
SiteCrawlFetchStates,
|
|
@@ -112,7 +112,7 @@ import {
|
|
|
112
112
|
roundPreservingTotal,
|
|
113
113
|
siteAuditPageFactorSchema,
|
|
114
114
|
wilsonInterval
|
|
115
|
-
} from "./chunk-
|
|
115
|
+
} from "./chunk-CF7G2HGX.js";
|
|
116
116
|
|
|
117
117
|
// src/demo-server.ts
|
|
118
118
|
import { dirname, join as join2 } from "path";
|
package/dist/index.js
CHANGED
|
@@ -3,14 +3,14 @@ import {
|
|
|
3
3
|
createGoogleMarketingCredentialStore,
|
|
4
4
|
createGoogleMarketingRuntime,
|
|
5
5
|
createServer
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-S46DWUNR.js";
|
|
7
7
|
import {
|
|
8
8
|
loadConfig
|
|
9
|
-
} from "./chunk-
|
|
10
|
-
import "./chunk-
|
|
11
|
-
import "./chunk-
|
|
12
|
-
import "./chunk-
|
|
13
|
-
import "./chunk-
|
|
9
|
+
} from "./chunk-GQAESNJT.js";
|
|
10
|
+
import "./chunk-OH7E7TJD.js";
|
|
11
|
+
import "./chunk-7G7YVTDA.js";
|
|
12
|
+
import "./chunk-HA2BAJ6Z.js";
|
|
13
|
+
import "./chunk-CF7G2HGX.js";
|
|
14
14
|
export {
|
|
15
15
|
GoogleMarketingRuntimeError,
|
|
16
16
|
createGoogleMarketingCredentialStore,
|
package/dist/mcp.js
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
import {
|
|
2
2
|
autoSyncSkills
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-JRBQFRNT.js";
|
|
4
4
|
import {
|
|
5
5
|
createApiClient,
|
|
6
6
|
createCanonryMcpServer
|
|
7
|
-
} from "./chunk-
|
|
8
|
-
import "./chunk-
|
|
7
|
+
} from "./chunk-GQAESNJT.js";
|
|
8
|
+
import "./chunk-7G7YVTDA.js";
|
|
9
9
|
import {
|
|
10
10
|
isReadOnlyKey,
|
|
11
11
|
updateCheckEnvOptOut
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-CF7G2HGX.js";
|
|
13
13
|
|
|
14
14
|
// src/mcp/cli.ts
|
|
15
15
|
import { randomUUID } from "crypto";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@canonry/canonry",
|
|
3
|
-
"version": "7.
|
|
3
|
+
"version": "7.11.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Self-hosted AI visibility (AEO) platform: track how ChatGPT, Claude, Gemini, and Perplexity cite your domain, join it with Search Console, GA4, server-side traffic, and paid media, and fix what you find through agent tools (CLI, REST, MCP). Local SQLite.",
|
|
6
6
|
"keywords": [
|
|
@@ -85,32 +85,32 @@
|
|
|
85
85
|
"@types/node-cron": "^3.0.11",
|
|
86
86
|
"tsup": "^8.5.1",
|
|
87
87
|
"tsx": "^4.19.0",
|
|
88
|
-
"@ainyc/canonry-web": "0.0.0",
|
|
89
|
-
"@ainyc/canonry-api-routes": "0.0.0",
|
|
90
|
-
"@ainyc/canonry-config": "0.0.0",
|
|
91
88
|
"@ainyc/canonry-api-client": "0.0.0",
|
|
92
89
|
"@ainyc/canonry-contracts": "0.0.0",
|
|
90
|
+
"@ainyc/canonry-api-routes": "0.0.0",
|
|
91
|
+
"@ainyc/canonry-config": "0.0.0",
|
|
93
92
|
"@ainyc/canonry-db": "0.0.0",
|
|
93
|
+
"@ainyc/canonry-web": "0.0.0",
|
|
94
94
|
"@ainyc/canonry-integration-bing": "0.0.0",
|
|
95
95
|
"@ainyc/canonry-integration-cloud-run": "0.0.0",
|
|
96
|
-
"@ainyc/canonry-integration-cloudflare-worker": "0.0.0",
|
|
97
96
|
"@ainyc/canonry-integration-cloudflare-queue": "0.0.0",
|
|
98
97
|
"@ainyc/canonry-integration-commoncrawl": "0.0.0",
|
|
99
98
|
"@ainyc/canonry-integration-google": "0.0.0",
|
|
100
99
|
"@ainyc/canonry-integration-google-ads": "0.0.0",
|
|
101
|
-
"@ainyc/canonry-integration-
|
|
100
|
+
"@ainyc/canonry-integration-cloudflare-worker": "0.0.0",
|
|
102
101
|
"@ainyc/canonry-integration-google-business-profile": "0.0.0",
|
|
102
|
+
"@ainyc/canonry-integration-google-tag-manager": "0.0.0",
|
|
103
|
+
"@ainyc/canonry-integration-google-places": "0.0.0",
|
|
103
104
|
"@ainyc/canonry-integration-openai-ads": "0.0.0",
|
|
104
105
|
"@ainyc/canonry-integration-traffic": "0.0.0",
|
|
105
106
|
"@ainyc/canonry-integration-wordpress": "0.0.0",
|
|
106
|
-
"@ainyc/canonry-intelligence": "0.0.0",
|
|
107
|
-
"@ainyc/canonry-integration-google-places": "0.0.0",
|
|
108
107
|
"@ainyc/canonry-provider-cdp": "0.0.0",
|
|
109
|
-
"@ainyc/canonry-
|
|
108
|
+
"@ainyc/canonry-intelligence": "0.0.0",
|
|
110
109
|
"@ainyc/canonry-provider-claude": "0.0.0",
|
|
111
110
|
"@ainyc/canonry-provider-local": "0.0.0",
|
|
112
|
-
"@ainyc/canonry-provider-openai": "0.0.0",
|
|
113
111
|
"@ainyc/canonry-provider-muse": "0.0.0",
|
|
112
|
+
"@ainyc/canonry-provider-gemini": "0.0.0",
|
|
113
|
+
"@ainyc/canonry-provider-openai": "0.0.0",
|
|
114
114
|
"@ainyc/canonry-provider-perplexity": "0.0.0",
|
|
115
115
|
"@ainyc/canonry-integration-typesafe": "0.0.0"
|
|
116
116
|
},
|