@canonry/canonry 5.28.1 → 5.29.1
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/assets/{AuditHistoryPanel-CWd9UN6L.js → AuditHistoryPanel-B_H7nIp7.js} +1 -1
- package/assets/assets/{BacklinksPage-B2gPTzyE.js → BacklinksPage-rhms6z2S.js} +1 -1
- package/assets/assets/{HistoryPage-xtkG8SZN.js → HistoryPage-CWPETgrG.js} +1 -1
- package/assets/assets/MeasurementPropertyPage-D9-54Je9.js +1 -0
- package/assets/assets/ProjectPage-eNVzxsZW.js +8 -0
- package/assets/assets/{RunRow-DnSo7Nle.js → RunRow-DQPW7FIF.js} +1 -1
- package/assets/assets/{RunsPage-FAEuo4Ra.js → RunsPage-BOM_RkNi.js} +1 -1
- package/assets/assets/{SettingsPage-C4OZ1HB9.js → SettingsPage-BDnT6wtM.js} +1 -1
- package/assets/assets/SiteHealthSection-lcZA1XpM.js +4 -0
- package/assets/assets/{TrafficPage-D03S6xF6.js → TrafficPage-D4nGSfXx.js} +2 -2
- package/assets/assets/{TrafficSourceDetailPage-DBu6oFFK.js → TrafficSourceDetailPage-CvZcCbic.js} +1 -1
- package/assets/assets/{extract-error-message-BuH2CCaJ.js → extract-error-message-BJ3f0StM.js} +1 -1
- package/assets/assets/index-Cncchurw.js +86 -0
- package/assets/assets/{react-sigma_core.esm.min-CxwZsgxR.js → react-sigma_core.esm.min-c7qzyLLe.js} +1 -1
- package/assets/assets/{v2-overview-adapter-DTCKxzZT.js → v2-overview-adapter-Dsd6dWtE.js} +1 -1
- package/assets/index.html +1 -1
- package/dist/{chunk-DX2JUC5H.js → chunk-ASYPQYVV.js} +3 -3
- package/dist/{chunk-KVQHG3WB.js → chunk-FKL5EGOW.js} +6302 -5914
- package/dist/{chunk-EP4STEPI.js → chunk-N2SVFXOB.js} +164 -96
- package/dist/{chunk-ONTEFAA7.js → chunk-PTTVDWMN.js} +57 -3
- package/dist/{chunk-7RKCDOWO.js → chunk-RHZKOXDZ.js} +263 -190
- package/dist/{chunk-MPICT6V7.js → chunk-WL2SHCPU.js} +3 -3
- package/dist/{chunk-FNGITGDF.js → chunk-XWBQWAVE.js} +2 -2
- package/dist/cli.js +134 -123
- package/dist/{demo-server-HWWIMGD6.js → demo-server-VGUIDC5T.js} +24 -32
- package/dist/index.js +6 -6
- package/dist/{intelligence-service-6LDMVI66.js → intelligence-service-IQA4U3RA.js} +2 -2
- package/dist/mcp.js +4 -4
- package/package.json +12 -12
- package/assets/assets/MeasurementPropertyPage-DxIMU3_T.js +0 -1
- package/assets/assets/ProjectPage-CMAFZq_s.js +0 -8
- package/assets/assets/SiteHealthSection-BzMxlz8-.js +0 -4
- package/assets/assets/index-Ba-Zs45G.js +0 -86
package/dist/cli.js
CHANGED
|
@@ -35,11 +35,11 @@ import {
|
|
|
35
35
|
trackCliCommandFinished,
|
|
36
36
|
trackEvent,
|
|
37
37
|
waitForServerRuntimeStartup
|
|
38
|
-
} from "./chunk-
|
|
38
|
+
} from "./chunk-N2SVFXOB.js";
|
|
39
39
|
import {
|
|
40
40
|
autoSyncSkills,
|
|
41
41
|
formatAutoSyncNotice
|
|
42
|
-
} from "./chunk-
|
|
42
|
+
} from "./chunk-ASYPQYVV.js";
|
|
43
43
|
import {
|
|
44
44
|
configExists,
|
|
45
45
|
createApiClient,
|
|
@@ -56,13 +56,13 @@ import {
|
|
|
56
56
|
saveConfig,
|
|
57
57
|
saveConfigPatch,
|
|
58
58
|
shouldPrintServeSkillsNudge
|
|
59
|
-
} from "./chunk-
|
|
59
|
+
} from "./chunk-XWBQWAVE.js";
|
|
60
60
|
import {
|
|
61
61
|
DEFAULT_DEMO_TRUSTED_PROXIES,
|
|
62
62
|
trustedProxiesProblem,
|
|
63
63
|
trustedProxyProblem
|
|
64
64
|
} from "./chunk-RB2F4D3Z.js";
|
|
65
|
-
import "./chunk-
|
|
65
|
+
import "./chunk-PTTVDWMN.js";
|
|
66
66
|
import {
|
|
67
67
|
CliError,
|
|
68
68
|
EXIT_SYSTEM_ERROR,
|
|
@@ -74,7 +74,7 @@ import {
|
|
|
74
74
|
runMeasurementDraftAction,
|
|
75
75
|
systemError,
|
|
76
76
|
usageError
|
|
77
|
-
} from "./chunk-
|
|
77
|
+
} from "./chunk-WL2SHCPU.js";
|
|
78
78
|
import {
|
|
79
79
|
CLOUDFLARE_WORKER_BINDINGS,
|
|
80
80
|
CLOUDFLARE_WORKER_GENERATED_MARKER,
|
|
@@ -89,7 +89,7 @@ import {
|
|
|
89
89
|
queries,
|
|
90
90
|
renderReportHtml,
|
|
91
91
|
runs
|
|
92
|
-
} from "./chunk-
|
|
92
|
+
} from "./chunk-RHZKOXDZ.js";
|
|
93
93
|
import {
|
|
94
94
|
AdsDeliverySnapshotStatuses,
|
|
95
95
|
AdsHistoricalCampaignRollupStatuses,
|
|
@@ -102,11 +102,13 @@ import {
|
|
|
102
102
|
CheckScopes,
|
|
103
103
|
CheckStatuses,
|
|
104
104
|
CitationStates,
|
|
105
|
+
GaMoverChangeBases,
|
|
105
106
|
MeasurementEvidenceShapes,
|
|
106
107
|
OUTSTANDING_PROVIDER_BATCH_STATUSES,
|
|
107
108
|
ProviderBatchStatuses,
|
|
108
109
|
READ_ONLY_SCOPE,
|
|
109
110
|
REPORT_PERIOD_OPTIONS,
|
|
111
|
+
RatioUnits,
|
|
110
112
|
ResearchRunStatuses,
|
|
111
113
|
RunKinds,
|
|
112
114
|
RunStatuses,
|
|
@@ -144,9 +146,9 @@ import {
|
|
|
144
146
|
formatGbpMetricLabel,
|
|
145
147
|
formatIsoDate,
|
|
146
148
|
formatMicros,
|
|
147
|
-
|
|
149
|
+
formatPercent,
|
|
148
150
|
formatRunErrorOneLine,
|
|
149
|
-
|
|
151
|
+
formatSignedPointDelta,
|
|
150
152
|
gbpNegativeReviewMaxStarsSchema,
|
|
151
153
|
googleAdsMetricsWindowSchema,
|
|
152
154
|
isVisibilityCompareClassMetric,
|
|
@@ -185,7 +187,7 @@ import {
|
|
|
185
187
|
visibilityCompareSelectionSchema,
|
|
186
188
|
visibilityReportRequestSchema,
|
|
187
189
|
winnabilityClassSchema
|
|
188
|
-
} from "./chunk-
|
|
190
|
+
} from "./chunk-FKL5EGOW.js";
|
|
189
191
|
|
|
190
192
|
// src/cli.ts
|
|
191
193
|
import { pathToFileURL } from "url";
|
|
@@ -450,7 +452,7 @@ function parseDemoTrustedProxies(values) {
|
|
|
450
452
|
async function demoCommand(options) {
|
|
451
453
|
const { host, port } = parseDemoListenOptions(options);
|
|
452
454
|
const trustProxy = parseDemoTrustedProxies(options.trustProxy);
|
|
453
|
-
const { createDemoServer } = await import("./demo-server-
|
|
455
|
+
const { createDemoServer } = await import("./demo-server-VGUIDC5T.js");
|
|
454
456
|
const app = await createDemoServer({ trustProxy });
|
|
455
457
|
let stopping = false;
|
|
456
458
|
const stop = () => {
|
|
@@ -686,7 +688,7 @@ function formatSummaryAndDomains(project, response) {
|
|
|
686
688
|
lines.push(`Target: ${s.targetDomain}`);
|
|
687
689
|
lines.push(`Linking domains: ${s.totalLinkingDomains}`);
|
|
688
690
|
lines.push(`Total hosts: ${s.totalHosts}`);
|
|
689
|
-
lines.push(`Top-10 share: ${s.top10HostsShare}`);
|
|
691
|
+
lines.push(`Top-10 share: ${formatPercent(Number(s.top10HostsShare))}`);
|
|
690
692
|
if (s.excludedLinkingDomains !== void 0 && s.excludedLinkingDomains > 0) {
|
|
691
693
|
lines.push(`Excluded: ${s.excludedLinkingDomains} crawler/proxy domains (${s.excludedHosts ?? 0} hosts)`);
|
|
692
694
|
}
|
|
@@ -1199,7 +1201,7 @@ async function bingCoverage(project, format) {
|
|
|
1199
1201
|
console.log(`
|
|
1200
1202
|
Bing Index Coverage for "${project}"
|
|
1201
1203
|
`);
|
|
1202
|
-
console.log(` SUMMARY: ${pctColor}${summary.indexed} / ${summary.total} pages indexed (${summary.percentage}
|
|
1204
|
+
console.log(` SUMMARY: ${pctColor}${summary.indexed} / ${summary.total} pages indexed (${formatPercent(summary.percentage, "percent")})${reset}${unknownNote}
|
|
1203
1205
|
`);
|
|
1204
1206
|
if (result.indexed.length > 0) {
|
|
1205
1207
|
console.log(` INDEXED (${result.indexed.length}):`);
|
|
@@ -1424,7 +1426,7 @@ async function bingPerformance(project, format) {
|
|
|
1424
1426
|
for (const row of rows.slice(0, 50)) {
|
|
1425
1427
|
const query = row.query.length > 38 ? row.query.slice(0, 35) + "..." : row.query;
|
|
1426
1428
|
console.log(
|
|
1427
|
-
` ${query.padEnd(40)}${String(row.clicks).padEnd(8)}${String(row.impressions).padEnd(8)}${(row.ctr
|
|
1429
|
+
` ${query.padEnd(40)}${String(row.clicks).padEnd(8)}${String(row.impressions).padEnd(8)}${formatPercent(row.ctr).padStart(6)} ${row.averagePosition.toFixed(1).padStart(5)}`
|
|
1428
1430
|
);
|
|
1429
1431
|
}
|
|
1430
1432
|
if (rows.length > 50) {
|
|
@@ -3609,7 +3611,7 @@ async function adsSummary(project, opts) {
|
|
|
3609
3611
|
console.log(`Structure: ${result.campaignCount} campaigns / ${result.adGroupCount} ad groups / ${result.adCount} ads`);
|
|
3610
3612
|
console.log(`Window: ${result.window.from ?? "\u2014"} \u2192 ${result.window.to ?? "\u2014"}${partialDayNote(result.window.inProgressDate)}`);
|
|
3611
3613
|
console.log(`Impressions: ${result.totals.impressions}`);
|
|
3612
|
-
console.log(`Clicks: ${result.totals.clicks}${result.totals.ctr != null ? ` (CTR ${(result.totals.ctr
|
|
3614
|
+
console.log(`Clicks: ${result.totals.clicks}${result.totals.ctr != null ? ` (CTR ${formatPercent(result.totals.ctr)})` : ""}`);
|
|
3613
3615
|
console.log(`Spend: ${formatMicros(result.totals.spendMicros, result.currencyCode ?? "USD")}${result.totals.cpcMicros != null ? ` (CPC ${formatMicros(result.totals.cpcMicros, result.currencyCode ?? "USD")})` : ""}`);
|
|
3614
3616
|
console.log(`Last synced: ${result.lastSyncedAt ?? "never"}`);
|
|
3615
3617
|
}
|
|
@@ -4233,8 +4235,7 @@ async function gaTraffic(project, opts) {
|
|
|
4233
4235
|
console.log(` Organic Sessions: ${result.totalOrganicSessions}`);
|
|
4234
4236
|
console.log(` Total Users: ${result.totalUsers ?? "unavailable for this range"}`);
|
|
4235
4237
|
if (result.aiSessionsDeduped > 0) {
|
|
4236
|
-
|
|
4237
|
-
console.log(` AI Sessions (deduped): ${result.aiSessionsDeduped} (${share}% of total)`);
|
|
4238
|
+
console.log(` AI Sessions (deduped): ${result.aiSessionsDeduped} (${result.aiSharePctDisplay} of total)`);
|
|
4238
4239
|
if (result.paidAiSessionsDeduped > 0) {
|
|
4239
4240
|
console.log(` Paid AI: ${result.paidAiSessionsDeduped} (${result.paidAiSharePctDisplay} of total)`);
|
|
4240
4241
|
}
|
|
@@ -4244,13 +4245,13 @@ async function gaTraffic(project, opts) {
|
|
|
4244
4245
|
const attrWidth = 12;
|
|
4245
4246
|
const classWidth = 8;
|
|
4246
4247
|
console.log(" AI REFERRAL SOURCES");
|
|
4247
|
-
console.log(` ${"SOURCE".padEnd(25)} ${"MEDIUM".padEnd(15)} ${"CLASS".padEnd(classWidth)} ${"ATTRIBUTION".padEnd(attrWidth)} ${"SESSIONS".padEnd(10)}`);
|
|
4248
|
-
console.log(` ${"\u2500".repeat(25)} ${"\u2500".repeat(15)} ${"\u2500".repeat(classWidth)} ${"\u2500".repeat(attrWidth)} ${"\u2500".repeat(10)}`);
|
|
4248
|
+
console.log(` ${"SOURCE".padEnd(25)} ${"MEDIUM".padEnd(15)} ${"CLASS".padEnd(classWidth)} ${"ATTRIBUTION".padEnd(attrWidth)} ${"SESSIONS".padEnd(10)} SHARE`);
|
|
4249
|
+
console.log(` ${"\u2500".repeat(25)} ${"\u2500".repeat(15)} ${"\u2500".repeat(classWidth)} ${"\u2500".repeat(attrWidth)} ${"\u2500".repeat(10)} ${"\u2500".repeat(6)}`);
|
|
4249
4250
|
for (const ref of result.aiReferrals) {
|
|
4250
4251
|
const dimLabel = ref.sourceDimension === "first_user" ? "first-visit" : ref.sourceDimension === "manual_utm" ? "utm" : "session";
|
|
4251
4252
|
const classLabel = ref.trafficClass === "paid" ? "paid" : "organic";
|
|
4252
4253
|
console.log(
|
|
4253
|
-
` ${ref.source.padEnd(25)} ${ref.medium.padEnd(15)} ${classLabel.padEnd(classWidth)} ${dimLabel.padEnd(attrWidth)} ${String(ref.sessions).padEnd(10)}`
|
|
4254
|
+
` ${ref.source.padEnd(25)} ${ref.medium.padEnd(15)} ${classLabel.padEnd(classWidth)} ${dimLabel.padEnd(attrWidth)} ${String(ref.sessions).padEnd(10)} ${formatPercent(ref.share)}`
|
|
4254
4255
|
);
|
|
4255
4256
|
}
|
|
4256
4257
|
console.log();
|
|
@@ -4273,16 +4274,15 @@ async function gaTraffic(project, opts) {
|
|
|
4273
4274
|
if (result.socialReferrals.length > 0) {
|
|
4274
4275
|
const chanWidth = 12;
|
|
4275
4276
|
if (result.socialSessions > 0) {
|
|
4276
|
-
|
|
4277
|
-
console.log(` Social Sessions: ${result.socialSessions} (${share}% of total)`);
|
|
4277
|
+
console.log(` Social Sessions: ${result.socialSessions} (${result.socialSharePctDisplay} of total)`);
|
|
4278
4278
|
}
|
|
4279
4279
|
console.log(" SOCIAL REFERRAL SOURCES");
|
|
4280
|
-
console.log(` ${"SOURCE".padEnd(25)} ${"MEDIUM".padEnd(15)} ${"CHANNEL".padEnd(chanWidth)} ${"SESSIONS".padEnd(10)}`);
|
|
4281
|
-
console.log(` ${"\u2500".repeat(25)} ${"\u2500".repeat(15)} ${"\u2500".repeat(chanWidth)} ${"\u2500".repeat(10)}`);
|
|
4280
|
+
console.log(` ${"SOURCE".padEnd(25)} ${"MEDIUM".padEnd(15)} ${"CHANNEL".padEnd(chanWidth)} ${"SESSIONS".padEnd(10)} SHARE`);
|
|
4281
|
+
console.log(` ${"\u2500".repeat(25)} ${"\u2500".repeat(15)} ${"\u2500".repeat(chanWidth)} ${"\u2500".repeat(10)} ${"\u2500".repeat(6)}`);
|
|
4282
4282
|
for (const ref of result.socialReferrals) {
|
|
4283
4283
|
const chanLabel = ref.channelGroup === "Paid Social" ? "paid" : "organic";
|
|
4284
4284
|
console.log(
|
|
4285
|
-
` ${ref.source.padEnd(25)} ${ref.medium.padEnd(15)} ${chanLabel.padEnd(chanWidth)} ${String(ref.sessions).padEnd(10)}`
|
|
4285
|
+
` ${ref.source.padEnd(25)} ${ref.medium.padEnd(15)} ${chanLabel.padEnd(chanWidth)} ${String(ref.sessions).padEnd(10)} ${formatPercent(ref.share)}`
|
|
4286
4286
|
);
|
|
4287
4287
|
}
|
|
4288
4288
|
console.log();
|
|
@@ -4290,12 +4290,12 @@ async function gaTraffic(project, opts) {
|
|
|
4290
4290
|
if (result.topPages.length > 0) {
|
|
4291
4291
|
const pageWidth = Math.min(60, Math.max(15, ...result.topPages.map((r) => r.landingPage.length)));
|
|
4292
4292
|
console.log(` TOP LANDING PAGES`);
|
|
4293
|
-
console.log(` ${"PAGE".padEnd(pageWidth)} ${"SESSIONS".padEnd(10)}${"ORGANIC".padEnd(10)}
|
|
4294
|
-
console.log(` ${"\u2500".repeat(pageWidth)} ${"\u2500".repeat(10)}${"\u2500".repeat(10)}`);
|
|
4293
|
+
console.log(` ${"PAGE".padEnd(pageWidth)} ${"SESSIONS".padEnd(10)}${"ORGANIC".padEnd(10)}ORGANIC %`);
|
|
4294
|
+
console.log(` ${"\u2500".repeat(pageWidth)} ${"\u2500".repeat(10)}${"\u2500".repeat(10)}${"\u2500".repeat(9)}`);
|
|
4295
4295
|
for (const row of result.topPages) {
|
|
4296
4296
|
const page = row.landingPage.length > pageWidth ? row.landingPage.slice(0, pageWidth - 3) + "..." : row.landingPage;
|
|
4297
4297
|
console.log(
|
|
4298
|
-
` ${page.padEnd(pageWidth)} ${String(row.sessions).padEnd(10)}${String(row.organicSessions).padEnd(10)}`
|
|
4298
|
+
` ${page.padEnd(pageWidth)} ${String(row.sessions).padEnd(10)}${String(row.organicSessions).padEnd(10)}${formatPercent(row.organicShare)}`
|
|
4299
4299
|
);
|
|
4300
4300
|
}
|
|
4301
4301
|
}
|
|
@@ -4488,6 +4488,19 @@ async function gaCoverage(project, format) {
|
|
|
4488
4488
|
);
|
|
4489
4489
|
}
|
|
4490
4490
|
}
|
|
4491
|
+
function fmtTrend(pct) {
|
|
4492
|
+
return pct === null ? "n/a" : `${pct >= 0 ? "+" : ""}${formatPercent(pct, "percent")}`;
|
|
4493
|
+
}
|
|
4494
|
+
function fmtMoverChange(mover) {
|
|
4495
|
+
switch (mover.changeBasis) {
|
|
4496
|
+
case GaMoverChangeBases.new:
|
|
4497
|
+
return "new";
|
|
4498
|
+
case GaMoverChangeBases["small-base"]:
|
|
4499
|
+
return `${mover.changeSessions > 0 ? "+" : ""}${mover.changeSessions} sessions`;
|
|
4500
|
+
case GaMoverChangeBases.percent:
|
|
4501
|
+
return fmtTrend(mover.changePct);
|
|
4502
|
+
}
|
|
4503
|
+
}
|
|
4491
4504
|
function windowLine(traffic) {
|
|
4492
4505
|
if (!traffic.windowStart || !traffic.windowEnd) return null;
|
|
4493
4506
|
const span = traffic.windowDays === null ? "" : ` (${traffic.windowDays} days)`;
|
|
@@ -4516,14 +4529,13 @@ async function gaSocialReferralSummary(project, opts) {
|
|
|
4516
4529
|
const trendWindow = windowLine(traffic);
|
|
4517
4530
|
if (trendWindow) console.log(`${trendWindow}
|
|
4518
4531
|
`);
|
|
4519
|
-
console.log(` Sessions: ${traffic.socialSessions} (${traffic.
|
|
4532
|
+
console.log(` Sessions: ${traffic.socialSessions} (${traffic.socialSharePctDisplay} of ${traffic.totalSessions} total)`);
|
|
4520
4533
|
console.log();
|
|
4521
|
-
const fmtTrend = (pct4) => pct4 === null ? "n/a" : `${pct4 >= 0 ? "+" : ""}${pct4}%`;
|
|
4522
4534
|
console.log(` 7d trend: ${fmtTrend(trend.trend7dPct)} (${trend.socialSessions7d} vs ${trend.socialSessionsPrev7d})`);
|
|
4523
4535
|
console.log(` 30d trend: ${fmtTrend(trend.trend30dPct)} (${trend.socialSessions30d} vs ${trend.socialSessionsPrev30d})`);
|
|
4524
4536
|
if (trend.biggestMover) {
|
|
4525
4537
|
const m = trend.biggestMover;
|
|
4526
|
-
console.log(` Mover: ${m.source} (${m
|
|
4538
|
+
console.log(` Mover: ${m.source} (${fmtMoverChange(m)}, ${m.sessionsPrev7d}\u2192${m.sessions7d})`);
|
|
4527
4539
|
}
|
|
4528
4540
|
console.log();
|
|
4529
4541
|
if (traffic.socialReferrals.length > 0) {
|
|
@@ -4552,7 +4564,7 @@ async function gaSocialReferralSummary(project, opts) {
|
|
|
4552
4564
|
const socialWindow = windowLine(traffic);
|
|
4553
4565
|
if (socialWindow) console.log(`${socialWindow}
|
|
4554
4566
|
`);
|
|
4555
|
-
console.log(` Sessions: ${traffic.socialSessions} (${traffic.
|
|
4567
|
+
console.log(` Sessions: ${traffic.socialSessions} (${traffic.socialSharePctDisplay} of ${traffic.totalSessions} total)`);
|
|
4556
4568
|
if (traffic.socialReferrals.length > 0) {
|
|
4557
4569
|
console.log();
|
|
4558
4570
|
console.log(" TOP SOURCES");
|
|
@@ -4565,7 +4577,6 @@ async function gaSocialReferralSummary(project, opts) {
|
|
|
4565
4577
|
async function gaAttribution(project, opts) {
|
|
4566
4578
|
const client = getClient7();
|
|
4567
4579
|
const traffic = await client.gaTraffic(project);
|
|
4568
|
-
const fmtTrend = (pct4) => pct4 === null ? "n/a" : `${pct4 >= 0 ? "+" : ""}${pct4}%`;
|
|
4569
4580
|
if (opts?.trend) {
|
|
4570
4581
|
const trend = await client.gaAttributionTrend(project);
|
|
4571
4582
|
if (isMachineFormat(opts.format)) {
|
|
@@ -4625,25 +4636,25 @@ async function gaAttribution(project, opts) {
|
|
|
4625
4636
|
console.log(` Total Sessions: ${traffic.totalSessions}`);
|
|
4626
4637
|
console.log(` Total Users: ${traffic.totalUsers ?? "unavailable for this range"}`);
|
|
4627
4638
|
console.log();
|
|
4628
|
-
console.log(
|
|
4629
|
-
console.log(` Organic Search: ${String(traffic.channelBreakdown.organic.sessions).padEnd(6)} (${traffic.channelBreakdown.organic.sharePctDisplay.padStart(
|
|
4630
|
-
console.log(` Social: ${String(traffic.channelBreakdown.social.sessions).padEnd(6)} (${traffic.channelBreakdown.social.sharePctDisplay.padStart(
|
|
4631
|
-
console.log(` Direct: ${String(traffic.channelBreakdown.direct.sessions).padEnd(6)} (${traffic.channelBreakdown.direct.sharePctDisplay.padStart(
|
|
4632
|
-
console.log(` AI Referrals: ${String(traffic.channelBreakdown.ai.sessions).padEnd(6)} (${traffic.channelBreakdown.ai.sharePctDisplay.padStart(
|
|
4639
|
+
console.log(` CHANNEL BREAKDOWN${" ".repeat(20)}7d trend 30d trend`);
|
|
4640
|
+
console.log(` Organic Search: ${String(traffic.channelBreakdown.organic.sessions).padEnd(6)} (${traffic.channelBreakdown.organic.sharePctDisplay.padStart(6)}) ${fmtTrend(trend.organic.trend7dPct).padEnd(12)} ${fmtTrend(trend.organic.trend30dPct)}`);
|
|
4641
|
+
console.log(` Social: ${String(traffic.channelBreakdown.social.sessions).padEnd(6)} (${traffic.channelBreakdown.social.sharePctDisplay.padStart(6)}) ${fmtTrend(trend.social.trend7dPct).padEnd(12)} ${fmtTrend(trend.social.trend30dPct)}`);
|
|
4642
|
+
console.log(` Direct: ${String(traffic.channelBreakdown.direct.sessions).padEnd(6)} (${traffic.channelBreakdown.direct.sharePctDisplay.padStart(6)}) ${fmtTrend(trend.direct.trend7dPct).padEnd(12)} ${fmtTrend(trend.direct.trend30dPct)}`);
|
|
4643
|
+
console.log(` AI Referrals: ${String(traffic.channelBreakdown.ai.sessions).padEnd(6)} (${traffic.channelBreakdown.ai.sharePctDisplay.padStart(6)}) ${fmtTrend(trend.ai.trend7dPct).padEnd(12)} ${fmtTrend(trend.ai.trend30dPct)} (lower bound \u2014 sessionSource only; referrer-stripped traffic falls under Direct)`);
|
|
4633
4644
|
if (traffic.paidAiSessionsBySession > 0) {
|
|
4634
|
-
console.log(` Paid AI: ${String(traffic.paidAiSessionsBySession).padEnd(6)} (${traffic.paidAiSharePctBySessionDisplay.padStart(
|
|
4645
|
+
console.log(` Paid AI: ${String(traffic.paidAiSessionsBySession).padEnd(6)} (${traffic.paidAiSharePctBySessionDisplay.padStart(6)})`);
|
|
4635
4646
|
}
|
|
4636
|
-
console.log(` Other: ${String(traffic.channelBreakdown.other.sessions).padEnd(6)} (${traffic.channelBreakdown.other.sharePctDisplay.padStart(
|
|
4647
|
+
console.log(` Other: ${String(traffic.channelBreakdown.other.sessions).padEnd(6)} (${traffic.channelBreakdown.other.sharePctDisplay.padStart(6)})`);
|
|
4637
4648
|
console.log(` \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500`);
|
|
4638
|
-
console.log(` Total: ${String(traffic.totalSessions).padEnd(6)}
|
|
4649
|
+
console.log(` Total: ${String(traffic.totalSessions).padEnd(6)}${" ".repeat(13)}${fmtTrend(trend.total.trend7dPct).padEnd(12)} ${fmtTrend(trend.total.trend30dPct)}`);
|
|
4639
4650
|
if (trend.aiBiggestMover) {
|
|
4640
4651
|
const m = trend.aiBiggestMover;
|
|
4641
4652
|
console.log(`
|
|
4642
|
-
AI Mover: ${m.source} (${m
|
|
4653
|
+
AI Mover: ${m.source} (${fmtMoverChange(m)}, ${m.sessionsPrev7d}\u2192${m.sessions7d} sessions/7d)`);
|
|
4643
4654
|
}
|
|
4644
4655
|
if (trend.socialBiggestMover) {
|
|
4645
4656
|
const m = trend.socialBiggestMover;
|
|
4646
|
-
console.log(` Social Mover: ${m.source} (${m
|
|
4657
|
+
console.log(` Social Mover: ${m.source} (${fmtMoverChange(m)}, ${m.sessionsPrev7d}\u2192${m.sessions7d} sessions/7d)`);
|
|
4647
4658
|
}
|
|
4648
4659
|
if (traffic.lastSyncedAt) {
|
|
4649
4660
|
console.log(`
|
|
@@ -5150,7 +5161,7 @@ async function gbpKeywords(project, opts) {
|
|
|
5150
5161
|
console.log("No GBP keyword impressions stored. Run `canonry gbp sync <project>` first.");
|
|
5151
5162
|
return;
|
|
5152
5163
|
}
|
|
5153
|
-
console.log(`${response.total} keyword(s), ${response.thresholdedPct}
|
|
5164
|
+
console.log(`${response.total} keyword(s), ${formatPercent(response.thresholdedPct, "percent")} privacy-thresholded. Top by impressions:`);
|
|
5154
5165
|
for (const k of response.keywords.slice(0, 15)) {
|
|
5155
5166
|
const val = k.valueCount !== null ? String(k.valueCount) : `<${k.valueThreshold ?? "?"}`;
|
|
5156
5167
|
console.log(` ${val.padStart(8)} ${k.keyword}`);
|
|
@@ -5271,9 +5282,9 @@ ${response.total} ${label}${shown}:`);
|
|
|
5271
5282
|
console.log(` ${r.updateTime.slice(0, 10)} ${stars}${where} ${r.reviewerName ?? "Anonymous"} ${text} [${r.origin}, ${r.alertState}]`);
|
|
5272
5283
|
}
|
|
5273
5284
|
}
|
|
5274
|
-
function fmtDelta(
|
|
5275
|
-
if (
|
|
5276
|
-
return `${
|
|
5285
|
+
function fmtDelta(pct) {
|
|
5286
|
+
if (pct === null) return "n/a";
|
|
5287
|
+
return `${pct >= 0 ? "+" : ""}${formatPercent(pct, "percent")}`;
|
|
5277
5288
|
}
|
|
5278
5289
|
async function gbpSummary(project, opts) {
|
|
5279
5290
|
const client = getClient8();
|
|
@@ -5299,7 +5310,7 @@ async function gbpSummary(project, opts) {
|
|
|
5299
5310
|
}
|
|
5300
5311
|
}
|
|
5301
5312
|
console.log(`
|
|
5302
|
-
Keywords: ${s.keywords.total} tracked, ${s.keywords.thresholdedPct}
|
|
5313
|
+
Keywords: ${s.keywords.total} tracked, ${formatPercent(s.keywords.thresholdedPct, "percent")} privacy-thresholded`);
|
|
5303
5314
|
console.log(`Place actions: ${s.placeActions.total} CTA(s) \u2014 reservation:${s.placeActions.hasReservationCta ? "yes" : "no"} booking:${s.placeActions.hasBookingCta ? "yes" : "no"} direct-merchant:${s.placeActions.hasDirectMerchantCta ? "yes" : "no"}`);
|
|
5304
5315
|
console.log(`Lodging API: ${s.lodging.lodgingLocationCount} profile(s), ${s.lodging.populatedLodgingCount} with readable groups, ${s.lodging.emptyLodgingCount} with 0 readable groups`);
|
|
5305
5316
|
const pc = s.profileCompleteness;
|
|
@@ -5654,13 +5665,10 @@ function performanceMicros(micros, currencyCode) {
|
|
|
5654
5665
|
if (currencyCode === null) return (micros / 1e6).toFixed(2);
|
|
5655
5666
|
return formatMicros(micros, currencyCode);
|
|
5656
5667
|
}
|
|
5657
|
-
function performanceRatio(ratio) {
|
|
5658
|
-
return ratio === null ? "\u2014" : `${(ratio * 100).toFixed(2)}%`;
|
|
5659
|
-
}
|
|
5660
5668
|
function performanceChange(ratio) {
|
|
5661
5669
|
if (ratio === null) return "";
|
|
5662
5670
|
const sign = ratio > 0 ? "+" : "";
|
|
5663
|
-
return ` (${sign}${(ratio
|
|
5671
|
+
return ` (${sign}${formatPercent(ratio)} vs prior period)`;
|
|
5664
5672
|
}
|
|
5665
5673
|
async function googleAdsPerformance(client, project, opts) {
|
|
5666
5674
|
const result = await client.getGoogleAdsPerformance(project, opts.window ? { window: opts.window } : {});
|
|
@@ -5676,9 +5684,9 @@ async function googleAdsPerformance(client, project, opts) {
|
|
|
5676
5684
|
console.log(`As of: ${result.source.asOfDate}${result.source.openDate ? ` (${result.source.openDate} still open, excluded)` : ""}`);
|
|
5677
5685
|
console.log(`Account: ${result.source.customerId} (${currency ?? "?"}, ${result.source.timeZone ?? "unknown zone"})`);
|
|
5678
5686
|
console.log(`Impressions: ${totals.impressions}${performanceChange(comparison?.change.impressions ?? null)}`);
|
|
5679
|
-
console.log(`Clicks: ${totals.clicks} (CTR ${
|
|
5687
|
+
console.log(`Clicks: ${totals.clicks} (CTR ${formatPercent(totals.ctr)})${performanceChange(comparison?.change.clicks ?? null)}`);
|
|
5680
5688
|
console.log(`Cost: ${performanceMicros(totals.costMicros, currency)} (CPC ${performanceMicros(totals.cpcMicros, currency)})${performanceChange(comparison?.change.costMicros ?? null)}`);
|
|
5681
|
-
console.log(`Conversions: ${totals.conversions} (rate ${
|
|
5689
|
+
console.log(`Conversions: ${totals.conversions} (rate ${formatPercent(totals.conversionRate)}, cost/conv ${performanceMicros(totals.costPerConversionMicros, currency)})`);
|
|
5682
5690
|
if (!comparison) {
|
|
5683
5691
|
console.log(`Comparison: unavailable (${result.comparisonUnavailableReason ?? "unknown"})`);
|
|
5684
5692
|
}
|
|
@@ -8296,7 +8304,7 @@ async function googlePerformanceDaily(project, opts) {
|
|
|
8296
8304
|
}
|
|
8297
8305
|
console.log(` Clicks: ${clicks.toLocaleString()}`);
|
|
8298
8306
|
console.log(` Impressions: ${impressions.toLocaleString()}`);
|
|
8299
|
-
console.log(` CTR: ${(ctr
|
|
8307
|
+
console.log(` CTR: ${formatPercent(ctr)}`);
|
|
8300
8308
|
console.log(` Position: ${position == null ? "\u2014" : position.toFixed(1)}`);
|
|
8301
8309
|
const fits = data.trends;
|
|
8302
8310
|
const trendLines = [];
|
|
@@ -8325,7 +8333,7 @@ Trend (least-squares fit over ${days} day${days === 1 ? "" : "s"}):`);
|
|
|
8325
8333
|
No period comparison: period comparison needs property-level daily data. Sync again, or pick a range covered by property totals.`
|
|
8326
8334
|
);
|
|
8327
8335
|
} else if (cmp) {
|
|
8328
|
-
const
|
|
8336
|
+
const pct = (ratio, prior, trailing, inverted) => {
|
|
8329
8337
|
if (ratio === null) {
|
|
8330
8338
|
if (prior !== null && trailing !== null && prior <= 0 && trailing > 0) {
|
|
8331
8339
|
return `new in last ${cmp.days} day${cmp.days === 1 ? "" : "s"}`;
|
|
@@ -8336,9 +8344,7 @@ No period comparison: period comparison needs property-level daily data. Sync ag
|
|
|
8336
8344
|
}
|
|
8337
8345
|
if (ratio === 0) return "no change";
|
|
8338
8346
|
const better = inverted ? ratio < 0 : ratio > 0;
|
|
8339
|
-
|
|
8340
|
-
const shown = magnitude < 0.1 ? "<0.1" : magnitude.toFixed(1);
|
|
8341
|
-
return `${ratio > 0 ? "+" : "-"}${shown}% ${better ? "better" : "worse"}`;
|
|
8347
|
+
return `${ratio > 0 ? "+" : "-"}${formatPercent(Math.abs(ratio))} ${better ? "better" : "worse"}`;
|
|
8342
8348
|
};
|
|
8343
8349
|
console.log(
|
|
8344
8350
|
`
|
|
@@ -8355,7 +8361,7 @@ Last ${cmp.days} day${cmp.days === 1 ? "" : "s"} (${cmp.trailing.startDate} to $
|
|
|
8355
8361
|
["CTR", cmp.change.ctr, cmp.prior.ctr, cmp.trailing.ctr, false],
|
|
8356
8362
|
["Position", cmp.change.position, cmp.prior.position, cmp.trailing.position, true]
|
|
8357
8363
|
]) {
|
|
8358
|
-
console.log(` ${`${label}:`.padEnd(13)}${
|
|
8364
|
+
console.log(` ${`${label}:`.padEnd(13)}${pct(ratio, prior, trailing, inverted)}`);
|
|
8359
8365
|
}
|
|
8360
8366
|
}
|
|
8361
8367
|
console.log();
|
|
@@ -8363,7 +8369,7 @@ Last ${cmp.days} day${cmp.days === 1 ? "" : "s"} (${cmp.trailing.startDate} to $
|
|
|
8363
8369
|
console.log(` ${"\u2500".repeat(12)}${"\u2500".repeat(10)}${"\u2500".repeat(12)}${"\u2500".repeat(10)}${"\u2500".repeat(9)}`);
|
|
8364
8370
|
for (const row of data.daily) {
|
|
8365
8371
|
console.log(
|
|
8366
|
-
` ${row.date.padEnd(12)}${row.clicks.toLocaleString().padStart(10)}${row.impressions.toLocaleString().padStart(12)}${(row.ctr
|
|
8372
|
+
` ${row.date.padEnd(12)}${row.clicks.toLocaleString().padStart(10)}${row.impressions.toLocaleString().padStart(12)}${formatPercent(row.ctr).padStart(10)}${(row.position == null ? "\u2014" : row.position.toFixed(1)).padStart(9)}`
|
|
8367
8373
|
);
|
|
8368
8374
|
}
|
|
8369
8375
|
}
|
|
@@ -8394,7 +8400,7 @@ async function googleTopPages(project, opts) {
|
|
|
8394
8400
|
for (const row of data.rows) {
|
|
8395
8401
|
const page = row.page.length > pageWidth ? row.page.slice(0, pageWidth - 3) + "..." : row.page;
|
|
8396
8402
|
console.log(
|
|
8397
|
-
` ${page.padEnd(pageWidth)}${row.clicks.toLocaleString().padStart(10)}${row.impressions.toLocaleString().padStart(12)}${(row.ctr
|
|
8403
|
+
` ${page.padEnd(pageWidth)}${row.clicks.toLocaleString().padStart(10)}${row.impressions.toLocaleString().padStart(12)}${formatPercent(row.ctr).padStart(10)}`
|
|
8398
8404
|
);
|
|
8399
8405
|
}
|
|
8400
8406
|
console.log();
|
|
@@ -8403,7 +8409,7 @@ async function googleTopPages(project, opts) {
|
|
|
8403
8409
|
console.log(`Property total (${days} day${days === 1 ? "" : "s"}, source: ${data.totalsSource}):`);
|
|
8404
8410
|
console.log(` Clicks: ${clicks.toLocaleString()}`);
|
|
8405
8411
|
console.log(` Impressions: ${impressions.toLocaleString()}`);
|
|
8406
|
-
console.log(` CTR: ${(ctr
|
|
8412
|
+
console.log(` CTR: ${formatPercent(ctr)}`);
|
|
8407
8413
|
console.log();
|
|
8408
8414
|
console.log(" The page rows above are a ranking. They do not add up to this total:");
|
|
8409
8415
|
console.log(" Google withholds rare queries and repeats an impression per page.");
|
|
@@ -8450,7 +8456,7 @@ async function googleQueryTotals(project, opts) {
|
|
|
8450
8456
|
for (const row of rows.slice(0, 50)) {
|
|
8451
8457
|
const query = row.query.length > 38 ? row.query.slice(0, 35) + "..." : row.query;
|
|
8452
8458
|
console.log(
|
|
8453
|
-
` ${query.padEnd(40)}${row.clicks.toLocaleString().padStart(8)}${row.impressions.toLocaleString().padStart(10)}${
|
|
8459
|
+
` ${query.padEnd(40)}${row.clicks.toLocaleString().padStart(8)}${row.impressions.toLocaleString().padStart(10)}${formatPercent(row.ctr).padStart(8)}${row.position.toFixed(1).padStart(7)}${String(row.days).padStart(6)}${showSource ? ` ${row.source}` : ""}`
|
|
8454
8460
|
);
|
|
8455
8461
|
}
|
|
8456
8462
|
if (rows.length > 50) {
|
|
@@ -8518,7 +8524,7 @@ async function googlePerformance(project, opts) {
|
|
|
8518
8524
|
for (const row of rows.slice(0, 50)) {
|
|
8519
8525
|
const query = row.query.length > 28 ? row.query.slice(0, 25) + "..." : row.query;
|
|
8520
8526
|
console.log(
|
|
8521
|
-
` ${row.date.padEnd(12)}${query.padEnd(30)}${String(row.clicks).padEnd(8)}${String(row.impressions).padEnd(8)}${(row.ctr
|
|
8527
|
+
` ${row.date.padEnd(12)}${query.padEnd(30)}${String(row.clicks).padEnd(8)}${String(row.impressions).padEnd(8)}${formatPercent(row.ctr).padStart(6)} ${row.position.toFixed(1).padStart(5)}`
|
|
8522
8528
|
);
|
|
8523
8529
|
}
|
|
8524
8530
|
if (rows.length > 50) {
|
|
@@ -8594,10 +8600,12 @@ async function googleCoverage(project, format) {
|
|
|
8594
8600
|
}
|
|
8595
8601
|
const pctColor = summary.percentage >= 80 ? "\x1B[32m" : summary.percentage >= 50 ? "\x1B[33m" : "\x1B[31m";
|
|
8596
8602
|
const reset = "\x1B[0m";
|
|
8603
|
+
const legacyServer = summary.indexedShare === void 0;
|
|
8604
|
+
const shareText = legacyServer ? `(${formatPercent(summary.percentage, "percent")})` : `(${formatPercent(summary.indexedShare)}) \xB7 ${summary.notIndexed} not indexed (${formatPercent(summary.notIndexedShare)})`;
|
|
8597
8605
|
console.log(`
|
|
8598
8606
|
Index Coverage for "${project}"
|
|
8599
8607
|
`);
|
|
8600
|
-
console.log(` SUMMARY: ${pctColor}${summary.indexed} / ${summary.total} pages indexed
|
|
8608
|
+
console.log(` SUMMARY: ${pctColor}${summary.indexed} / ${summary.total} pages indexed ${shareText}${reset}
|
|
8601
8609
|
`);
|
|
8602
8610
|
if (result.indexed.length > 0) {
|
|
8603
8611
|
console.log(` INDEXED (${result.indexed.length}):`);
|
|
@@ -10582,7 +10590,7 @@ function unattributedText(metric) {
|
|
|
10582
10590
|
}
|
|
10583
10591
|
function metricText(metric) {
|
|
10584
10592
|
if (metric.state === "unavailable") return METRIC_REASONS[metric.reason] ?? `not measured (${metric.reason})`;
|
|
10585
|
-
const percent =
|
|
10593
|
+
const percent = formatPercent(metric.value);
|
|
10586
10594
|
return metric.numerator === void 0 || metric.denominator === void 0 ? percent : `${metric.numerator} of ${metric.denominator} (${percent})`;
|
|
10587
10595
|
}
|
|
10588
10596
|
async function showMeasurementProperty(project, opts) {
|
|
@@ -11484,7 +11492,6 @@ function printMetrics(data) {
|
|
|
11484
11492
|
console.log(`
|
|
11485
11493
|
Citation Rate Trends (${data.window})`);
|
|
11486
11494
|
console.log("\u2500".repeat(50));
|
|
11487
|
-
const pct4 = (n) => `${(n * 100).toFixed(1)}%`;
|
|
11488
11495
|
const modelChangeNotice = buildModelChangeNotice(readModelPointerChanges(data));
|
|
11489
11496
|
if (modelChangeNotice?.kind === "change") {
|
|
11490
11497
|
console.log(`
|
|
@@ -11492,13 +11499,14 @@ Citation Rate Trends (${data.window})`);
|
|
|
11492
11499
|
console.log(` ${modelChangeNotice.text}`);
|
|
11493
11500
|
console.log("");
|
|
11494
11501
|
}
|
|
11495
|
-
console.log(` Overall: ${
|
|
11502
|
+
console.log(` Overall: ${formatPercent(data.overall.citationRate)} (${data.overall.cited}/${data.overall.total})`);
|
|
11496
11503
|
console.log(` Trend: ${data.trend}`);
|
|
11504
|
+
printWindowChange(data);
|
|
11497
11505
|
if (Object.keys(data.byProvider).length > 0) {
|
|
11498
11506
|
console.log(`
|
|
11499
11507
|
By Provider:`);
|
|
11500
11508
|
for (const [provider, metric] of Object.entries(data.byProvider)) {
|
|
11501
|
-
console.log(` ${provider.padEnd(10)} ${
|
|
11509
|
+
console.log(` ${provider.padEnd(10)} ${formatPercent(metric.citationRate).padStart(6)} (${metric.cited}/${metric.total})`);
|
|
11502
11510
|
}
|
|
11503
11511
|
}
|
|
11504
11512
|
if (data.buckets.length > 0) {
|
|
@@ -11506,7 +11514,7 @@ Citation Rate Trends (${data.window})`);
|
|
|
11506
11514
|
Timeline (dates in UTC):`);
|
|
11507
11515
|
for (const bucket of data.buckets) {
|
|
11508
11516
|
const bar = bucket.total > 0 ? "\u2588".repeat(Math.round(bucket.citationRate * 20)) : "";
|
|
11509
|
-
console.log(` ${bucketDates(bucket).padEnd(BUCKET_DATE_WIDTH)} ${
|
|
11517
|
+
console.log(` ${bucketDates(bucket).padEnd(BUCKET_DATE_WIDTH)} ${formatPercent(bucket.citationRate).padStart(6)} ${bar}`);
|
|
11510
11518
|
}
|
|
11511
11519
|
}
|
|
11512
11520
|
const providersInBuckets = [...new Set(data.buckets.flatMap((b) => Object.keys(b.byProvider ?? {})))].sort();
|
|
@@ -11519,7 +11527,7 @@ Citation Rate Trends (${data.window})`);
|
|
|
11519
11527
|
const metric = bucket.byProvider?.[provider];
|
|
11520
11528
|
if (!metric) continue;
|
|
11521
11529
|
const bar = metric.total > 0 ? "\u2588".repeat(Math.round(metric.citationRate * 20)) : "";
|
|
11522
|
-
console.log(` ${bucketDates(bucket).padEnd(BUCKET_DATE_WIDTH)} ${
|
|
11530
|
+
console.log(` ${bucketDates(bucket).padEnd(BUCKET_DATE_WIDTH)} ${formatPercent(metric.citationRate).padStart(6)} ${bar}`);
|
|
11523
11531
|
}
|
|
11524
11532
|
}
|
|
11525
11533
|
}
|
|
@@ -11567,6 +11575,22 @@ Citation Rate Trends (${data.window})`);
|
|
|
11567
11575
|
}
|
|
11568
11576
|
}
|
|
11569
11577
|
}
|
|
11578
|
+
function printWindowChange(data) {
|
|
11579
|
+
const windowChange = data.windowChange;
|
|
11580
|
+
if (!windowChange) return;
|
|
11581
|
+
const shareScope = data.mentionShareScope === "non-brand" ? "non-brand queries" : "pooled queries \xB7 classification unavailable";
|
|
11582
|
+
const series = [
|
|
11583
|
+
["Mentioned", windowChange.mentionRate],
|
|
11584
|
+
["Cited", windowChange.citationRate],
|
|
11585
|
+
[`Mention share \xB7 ${shareScope}`, windowChange.mentionShare]
|
|
11586
|
+
];
|
|
11587
|
+
console.log(`
|
|
11588
|
+
Change Across the Window (first \u2192 latest bucket):`);
|
|
11589
|
+
for (const [label, change] of series) {
|
|
11590
|
+
const text = change ? `${formatPercent(change.first)} \u2192 ${formatPercent(change.latest)} (${formatSignedPointDelta(change.delta)})` : "fewer than two buckets to compare";
|
|
11591
|
+
console.log(` ${label}: ${text}`);
|
|
11592
|
+
}
|
|
11593
|
+
}
|
|
11570
11594
|
function readServedModelAttribution(data) {
|
|
11571
11595
|
const legacyCompatible = data;
|
|
11572
11596
|
return legacyCompatible.servedModelAttribution ?? {};
|
|
@@ -11626,9 +11650,8 @@ Source Origin Breakdown`);
|
|
|
11626
11650
|
return;
|
|
11627
11651
|
}
|
|
11628
11652
|
for (const cat of data.overall) {
|
|
11629
|
-
const pct4 = `${(cat.percentage * 100).toFixed(1)}%`;
|
|
11630
11653
|
const domains = cat.topDomains.slice(0, 3).map((d) => d.domain).join(", ");
|
|
11631
|
-
console.log(` ${cat.label.padEnd(20)} ${
|
|
11654
|
+
console.log(` ${cat.label.padEnd(20)} ${formatPercent(cat.percentage).padStart(6)} (${cat.count}) ${domains}`);
|
|
11632
11655
|
}
|
|
11633
11656
|
}
|
|
11634
11657
|
|
|
@@ -11659,7 +11682,6 @@ Usage: ${SOURCES_USAGE}`, {
|
|
|
11659
11682
|
details: { command: "sources", usage: SOURCES_USAGE, option: "include-by-query", value }
|
|
11660
11683
|
});
|
|
11661
11684
|
}
|
|
11662
|
-
var pct = (n) => `${(n * 100).toFixed(1)}%`;
|
|
11663
11685
|
async function showSources(project, options) {
|
|
11664
11686
|
if (options.limit !== void 0 && (!Number.isInteger(options.limit) || options.limit <= 0)) {
|
|
11665
11687
|
throw usageError(`Error: --limit must be a positive integer
|
|
@@ -11731,12 +11753,12 @@ function describeScope(data) {
|
|
|
11731
11753
|
function printSurfaceClasses(list) {
|
|
11732
11754
|
for (const c of list.bySurfaceClass) {
|
|
11733
11755
|
const noun = c.domainCount === 1 ? "domain" : "domains";
|
|
11734
|
-
console.log(` ${c.label.padEnd(28)} ${
|
|
11756
|
+
console.log(` ${c.label.padEnd(28)} ${formatPercent(c.percentage).padStart(6)} (${c.count}) ${c.domainCount} ${noun}`);
|
|
11735
11757
|
}
|
|
11736
11758
|
}
|
|
11737
11759
|
function printRankedEntries(list, indent = "") {
|
|
11738
11760
|
for (const e of list.entries) {
|
|
11739
|
-
console.log(`${indent} ${e.domain.padEnd(32)} ${String(e.count).padStart(4)} ${
|
|
11761
|
+
console.log(`${indent} ${e.domain.padEnd(32)} ${String(e.count).padStart(4)} ${formatPercent(e.percentage).padStart(6)} ${e.surfaceClass}`);
|
|
11740
11762
|
}
|
|
11741
11763
|
if (list.truncatedDomainCount > 0) {
|
|
11742
11764
|
console.log(`${indent} \u2026 +${list.truncatedDomainCount} more domains (${list.truncatedCitedSlots} cited slots)`);
|
|
@@ -14670,9 +14692,9 @@ async function showHealth(project, opts) {
|
|
|
14670
14692
|
console.log("Date Mention Rate Mentioned/Total Cited Rate Cited/Total");
|
|
14671
14693
|
console.log("\u2500".repeat(86));
|
|
14672
14694
|
for (const snap of snapshots) {
|
|
14673
|
-
const mRate = (snap.overallMentionRate
|
|
14695
|
+
const mRate = formatPercent(snap.overallMentionRate).padStart(6);
|
|
14674
14696
|
const mRatio = `${snap.mentionedPairs}/${snap.totalPairs}`.padEnd(15);
|
|
14675
|
-
const cRate = (snap.overallCitedRate
|
|
14697
|
+
const cRate = formatPercent(snap.overallCitedRate).padStart(6);
|
|
14676
14698
|
const cRatio = `${snap.citedPairs}/${snap.totalPairs}`;
|
|
14677
14699
|
const date = snap.createdAt.slice(0, 19).padEnd(25);
|
|
14678
14700
|
console.log(`${date} ${mRate} ${mRatio} ${cRate} ${cRatio}`);
|
|
@@ -14688,17 +14710,13 @@ async function showHealth(project, opts) {
|
|
|
14688
14710
|
console.log("No health data yet \u2014 run a sweep first (canonry run <project>).");
|
|
14689
14711
|
return;
|
|
14690
14712
|
}
|
|
14691
|
-
|
|
14692
|
-
|
|
14693
|
-
console.log(`Health: ${mentionRate}% mentioned (${health.mentionedPairs}/${health.totalPairs} pairs)`);
|
|
14694
|
-
console.log(` ${citedRate}% cited (${health.citedPairs}/${health.totalPairs} pairs)`);
|
|
14713
|
+
console.log(`Health: ${formatPercent(health.overallMentionRate)} mentioned (${health.mentionedPairs}/${health.totalPairs} pairs)`);
|
|
14714
|
+
console.log(` ${formatPercent(health.overallCitedRate)} cited (${health.citedPairs}/${health.totalPairs} pairs)`);
|
|
14695
14715
|
console.log("");
|
|
14696
14716
|
if (health.providerBreakdown && Object.keys(health.providerBreakdown).length > 0) {
|
|
14697
14717
|
console.log("Provider Breakdown:");
|
|
14698
14718
|
for (const [provider, stats] of Object.entries(health.providerBreakdown)) {
|
|
14699
|
-
|
|
14700
|
-
const pCited = (stats.citedRate * 100).toFixed(1);
|
|
14701
|
-
console.log(` ${provider.padEnd(15)} ${pMention}% mentioned (${stats.mentioned}/${stats.total}) ${pCited}% cited (${stats.cited}/${stats.total})`);
|
|
14719
|
+
console.log(` ${provider.padEnd(15)} ${formatPercent(stats.mentionRate)} mentioned (${stats.mentioned}/${stats.total}) ${formatPercent(stats.citedRate)} cited (${stats.cited}/${stats.total})`);
|
|
14702
14720
|
}
|
|
14703
14721
|
}
|
|
14704
14722
|
}
|
|
@@ -14798,8 +14816,8 @@ function renderHuman2(overview) {
|
|
|
14798
14816
|
printScore("Competitor press.", scores.competitorPressure);
|
|
14799
14817
|
printScore("Run status ", scores.runStatus);
|
|
14800
14818
|
console.log(`
|
|
14801
|
-
Queries cited: ${queryCounts.citedQueries}/${queryCounts.totalQueries} (${
|
|
14802
|
-
console.log(` Queries mentioned: ${queryCounts.mentionedQueries}/${queryCounts.totalQueries} (${
|
|
14819
|
+
Queries cited: ${queryCounts.citedQueries}/${queryCounts.totalQueries} (${formatPercent(queryCounts.citedRate)})`);
|
|
14820
|
+
console.log(` Queries mentioned: ${queryCounts.mentionedQueries}/${queryCounts.totalQueries} (${formatPercent(queryCounts.mentionRate)})`);
|
|
14803
14821
|
if (movementComparison.hasPreviousRun) {
|
|
14804
14822
|
const comparisonLabel = movementComparison.querySetChanged ? `changed (+${movementComparison.addedQueryCount} added, -${movementComparison.removedQueryCount} removed); movement compares ${movementComparison.comparableQueryCount} shared` : `unchanged; ${movementComparison.comparableQueryCount} comparable`;
|
|
14805
14823
|
console.log(` Query basket: ${comparisonLabel}`);
|
|
@@ -14811,14 +14829,14 @@ function renderHuman2(overview) {
|
|
|
14811
14829
|
if (providers.length > 0) {
|
|
14812
14830
|
console.log("\n Providers:");
|
|
14813
14831
|
for (const p of providers) {
|
|
14814
|
-
console.log(` ${p.provider.padEnd(12)} ${p.cited}/${p.total} (${
|
|
14832
|
+
console.log(` ${p.provider.padEnd(12)} ${p.cited}/${p.total} (${formatPercent(p.citedRate)})`);
|
|
14815
14833
|
}
|
|
14816
14834
|
}
|
|
14817
14835
|
if (providerScores.length > 0) {
|
|
14818
14836
|
console.log("\n Models:");
|
|
14819
14837
|
for (const m of providerScores) {
|
|
14820
14838
|
const label = `${m.provider}/${m.model ?? "unknown"}`.padEnd(28);
|
|
14821
|
-
console.log(` ${label} ${m.cited}/${m.total} (${m.score}
|
|
14839
|
+
console.log(` ${label} ${m.cited}/${m.total} (${formatPercent(m.score, "percent")})`);
|
|
14822
14840
|
}
|
|
14823
14841
|
}
|
|
14824
14842
|
if (transitions.since) {
|
|
@@ -14840,7 +14858,7 @@ function renderHuman2(overview) {
|
|
|
14840
14858
|
}
|
|
14841
14859
|
if (health) {
|
|
14842
14860
|
console.log(`
|
|
14843
|
-
Health: ${
|
|
14861
|
+
Health: ${formatPercent(health.overallCitedRate)} cited (${health.citedPairs}/${health.totalPairs} pairs)`);
|
|
14844
14862
|
}
|
|
14845
14863
|
if (topInsights.length > 0) {
|
|
14846
14864
|
console.log("\n Top insights:");
|
|
@@ -14853,7 +14871,7 @@ function renderHuman2(overview) {
|
|
|
14853
14871
|
Run history (last ${runHistory.length}):`);
|
|
14854
14872
|
for (const point of runHistory) {
|
|
14855
14873
|
const bar = "\u2588".repeat(Math.round(point.citationRate / 10));
|
|
14856
|
-
console.log(` ${point.createdAt.slice(0, 10)} ${
|
|
14874
|
+
console.log(` ${point.createdAt.slice(0, 10)} ${formatPercent(point.citationRate, "percent").padStart(6)} ${bar}`);
|
|
14857
14875
|
}
|
|
14858
14876
|
}
|
|
14859
14877
|
if (suggestedQueries.rows.length > 0) {
|
|
@@ -14873,23 +14891,19 @@ function printScore(prefix, score) {
|
|
|
14873
14891
|
console.log(` ${prefix} ${tone} ${value} ${score.delta}`);
|
|
14874
14892
|
}
|
|
14875
14893
|
function printMentionShareBreakdown(mentionShare) {
|
|
14876
|
-
const
|
|
14877
|
-
|
|
14878
|
-
const
|
|
14879
|
-
if (
|
|
14880
|
-
const
|
|
14881
|
-
console.log(` you${" ".repeat(28)} ${
|
|
14882
|
-
for (const row of
|
|
14883
|
-
|
|
14884
|
-
console.log(` ${row.domain.padEnd(30)} ${row.mentionSnapshots} mentions (${pct4}% of combined)`);
|
|
14894
|
+
const legacyCompatible = mentionShare.breakdown;
|
|
14895
|
+
const ranking = legacyCompatible.ranking ?? [];
|
|
14896
|
+
const project = ranking.find((row) => row.kind === "project");
|
|
14897
|
+
if (!project) return;
|
|
14898
|
+
const competitors = ranking.filter((row) => row.kind === "competitor");
|
|
14899
|
+
console.log(` you${" ".repeat(28)} ${project.mentionSnapshots} mentions (${formatPercent(project.share)} of combined)`);
|
|
14900
|
+
for (const row of competitors.slice(0, 3)) {
|
|
14901
|
+
console.log(` ${(row.domain ?? "").padEnd(30)} ${row.mentionSnapshots} mentions (${formatPercent(row.share)} of combined)`);
|
|
14885
14902
|
}
|
|
14886
|
-
if (
|
|
14887
|
-
console.log(` + ${
|
|
14903
|
+
if (competitors.length > 3) {
|
|
14904
|
+
console.log(` + ${competitors.length - 3} more competitor${competitors.length - 3 === 1 ? "" : "s"} (--format json for full breakdown)`);
|
|
14888
14905
|
}
|
|
14889
14906
|
}
|
|
14890
|
-
function pct2(value) {
|
|
14891
|
-
return `${(value * 100).toFixed(1)}%`;
|
|
14892
|
-
}
|
|
14893
14907
|
|
|
14894
14908
|
// src/commands/search.ts
|
|
14895
14909
|
async function searchProject(project, opts) {
|
|
@@ -15220,9 +15234,9 @@ async function listContentGaps(project, opts) {
|
|
|
15220
15234
|
console.log(`${response.gaps.length} gap${response.gaps.length === 1 ? "" : "s"} found`);
|
|
15221
15235
|
console.log("");
|
|
15222
15236
|
for (const gap of response.gaps) {
|
|
15223
|
-
const missPct =
|
|
15224
|
-
console.log(`${missPct.padStart(
|
|
15225
|
-
console.log(`
|
|
15237
|
+
const missPct = formatPercent(gap.missRate);
|
|
15238
|
+
console.log(`${missPct.padStart(6)} ${gap.competitorCount} competitor(s) ${gap.query}`);
|
|
15239
|
+
console.log(` competitors: ${gap.competitorDomains.join(", ")}`);
|
|
15226
15240
|
console.log("");
|
|
15227
15241
|
}
|
|
15228
15242
|
}
|
|
@@ -16826,10 +16840,10 @@ async function technicalAeoScore(project, opts) {
|
|
|
16826
16840
|
lines.push(`As of ${score.auditedAt}`);
|
|
16827
16841
|
if (score.factors.length > 0) {
|
|
16828
16842
|
lines.push("");
|
|
16829
|
-
lines.push(`${"Factor".padEnd(32)}${"
|
|
16843
|
+
lines.push(`${"Factor".padEnd(32)}${"Share".padStart(7)}${"Avg".padStart(6)}${"Status".padStart(9)} Pass/Part/Fail`);
|
|
16830
16844
|
for (const f of score.factors) {
|
|
16831
16845
|
lines.push(
|
|
16832
|
-
`${f.name.slice(0, 31).padEnd(32)}${
|
|
16846
|
+
`${f.name.slice(0, 31).padEnd(32)}${formatPercent(f.sharePct, RatioUnits.percent).padStart(7)}${String(f.avgScore).padStart(6)}${f.status.padStart(9)} ${f.pagesPassing}/${f.pagesPartial}/${f.pagesFailing}`
|
|
16833
16847
|
);
|
|
16834
16848
|
}
|
|
16835
16849
|
}
|
|
@@ -17117,7 +17131,8 @@ async function technicalAeoPageAudit(project, opts) {
|
|
|
17117
17131
|
if (res.factors.length > 0) {
|
|
17118
17132
|
lines.push("", "Factors:");
|
|
17119
17133
|
for (const factor of res.factors) {
|
|
17120
|
-
|
|
17134
|
+
const share = typeof factor.sharePct === "number" ? ` \xB7 worth ${formatPercent(factor.sharePct, RatioUnits.percent)} of the page score` : "";
|
|
17135
|
+
lines.push(` ${factor.name}: ${factor.score}/100 (${factor.status})${share}`);
|
|
17121
17136
|
for (const finding of factor.findings) lines.push(` [${finding.code}] ${finding.message}`);
|
|
17122
17137
|
for (const recommendation of factor.recommendations) lines.push(` Fix: ${recommendation}`);
|
|
17123
17138
|
}
|
|
@@ -17810,9 +17825,6 @@ async function showVisibilityStats(project, opts) {
|
|
|
17810
17825
|
}
|
|
17811
17826
|
printVisibilityStats(data);
|
|
17812
17827
|
}
|
|
17813
|
-
function pct3(rate) {
|
|
17814
|
-
return rate === null ? "\u2014" : formatRatio(rate);
|
|
17815
|
-
}
|
|
17816
17828
|
async function showVisibilityCompare(project, opts) {
|
|
17817
17829
|
if (!opts.from || !opts.to) throw new Error("visibility-compare requires --from <YYYY-MM> and --to <YYYY-MM>");
|
|
17818
17830
|
const client = createApiClient();
|
|
@@ -17829,8 +17841,7 @@ function periodCell(p) {
|
|
|
17829
17841
|
return `unavailable: no competitive frame (${p.numerator} observed)`;
|
|
17830
17842
|
}
|
|
17831
17843
|
if (p.point === null || p.ciLow === null || p.ciHigh === null) return "no data";
|
|
17832
|
-
|
|
17833
|
-
return `${p1(p.point)} [${p1(p.ciLow)}, ${p1(p.ciHigh)}]`;
|
|
17844
|
+
return `${formatPercent(p.point)} [${formatPercent(p.ciLow)}, ${formatPercent(p.ciHigh)}]`;
|
|
17834
17845
|
}
|
|
17835
17846
|
function verdictCell(m) {
|
|
17836
17847
|
switch (m.verdict) {
|
|
@@ -17940,9 +17951,9 @@ function printVisibilityStats(data) {
|
|
|
17940
17951
|
const rows = data.queries.map((q) => ({
|
|
17941
17952
|
label: q.query,
|
|
17942
17953
|
cited: citedCell(q),
|
|
17943
|
-
citedPct:
|
|
17954
|
+
citedPct: formatPercent(q.citedRate),
|
|
17944
17955
|
ment: mentionedCell(q),
|
|
17945
|
-
mentPct:
|
|
17956
|
+
mentPct: formatPercent(q.mentionRate)
|
|
17946
17957
|
}));
|
|
17947
17958
|
const queryWidth = Math.max(7, ...rows.map((r) => r.label.length));
|
|
17948
17959
|
const citedWidth = Math.max(7, ...rows.map((r) => r.cited.length));
|
|
@@ -17972,9 +17983,9 @@ function printVisibilityStats(data) {
|
|
|
17972
17983
|
[
|
|
17973
17984
|
"TOTAL".padEnd(queryWidth),
|
|
17974
17985
|
citedCell(data.totals).padEnd(citedWidth),
|
|
17975
|
-
|
|
17986
|
+
formatPercent(data.totals.citedRate).padStart(7),
|
|
17976
17987
|
mentionedCell(data.totals).padEnd(mentWidth),
|
|
17977
|
-
|
|
17988
|
+
formatPercent(data.totals.mentionRate).padStart(7)
|
|
17978
17989
|
].join(" ")
|
|
17979
17990
|
);
|
|
17980
17991
|
if (data.groupBy === "provider" && data.byProvider && data.byProvider.length > 0) {
|
|
@@ -17986,9 +17997,9 @@ function printVisibilityStats(data) {
|
|
|
17986
17997
|
[
|
|
17987
17998
|
` ${p.provider}`.padEnd(provWidth + 2),
|
|
17988
17999
|
citedCell(p).padEnd(citedWidth),
|
|
17989
|
-
|
|
18000
|
+
formatPercent(p.citedRate).padStart(7),
|
|
17990
18001
|
mentionedCell(p).padEnd(mentWidth),
|
|
17991
|
-
|
|
18002
|
+
formatPercent(p.mentionRate).padStart(7)
|
|
17992
18003
|
].join(" ")
|
|
17993
18004
|
);
|
|
17994
18005
|
}
|
|
@@ -17996,7 +18007,7 @@ function printVisibilityStats(data) {
|
|
|
17996
18007
|
const sov = data.shareOfVoice;
|
|
17997
18008
|
if (sov) {
|
|
17998
18009
|
console.log("");
|
|
17999
|
-
const pctStr = sov.availability !== void 0 ? shareOfVoiceLabel(sov.percent, sov) : sov.percent !== null ?
|
|
18010
|
+
const pctStr = sov.availability !== void 0 ? shareOfVoiceLabel(sov.percent, sov) : sov.percent !== null ? formatPercent(sov.percent, "percent") : sov.competitorCount === 0 ? "\u2014 (no competitors configured)" : sov.snapshotsWithAnswerText === 0 ? "\u2014 (no answer text in scope)" : "\u2014 (no brands mentioned in scope)";
|
|
18000
18011
|
const scope = sov.queryClass === "pooled" ? "pooled queries \xB7 classification unavailable" : `${sov.queryClass} queries`;
|
|
18001
18012
|
console.log(
|
|
18002
18013
|
`Share of voice (${scope}${sov.measurementScope === "all-markets" ? " \xB7 all markets" : ""}): ${pctStr} (you ${sov.projectMentions} vs competitors ${sov.competitorMentions} brand mentions across ${sov.snapshotsWithAnswerText} answers)`
|