@canonry/canonry 5.20.4 → 5.22.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/portfolio-analysis.md +1 -1
- package/assets/agent-workspace/skills/aero/references/reporting.md +9 -4
- package/assets/agent-workspace/skills/canonry/references/canonry-cli.md +4 -1
- package/assets/assets/{AuditHistoryPanel-BSh3Oezj.js → AuditHistoryPanel-teTDC-4-.js} +1 -1
- package/assets/assets/{BacklinksPage-DQ59dhCx.js → BacklinksPage-Bqm7bido.js} +1 -1
- package/assets/assets/{HistoryPage-BBvgid3o.js → HistoryPage-IcqwPBmt.js} +1 -1
- package/assets/assets/{MeasurementPropertyPage-Dmb18JbT.js → MeasurementPropertyPage-BLpptT3_.js} +1 -1
- package/assets/assets/{ProjectPage-CPg0q2Dy.js → ProjectPage-nn2Y9H-m.js} +1 -1
- package/assets/assets/{RunRow-BK8sZCID.js → RunRow-S_SCHr0o.js} +1 -1
- package/assets/assets/{RunsPage-CIcVBTdP.js → RunsPage-DFiif626.js} +1 -1
- package/assets/assets/{SettingsPage-Bc3aR-gz.js → SettingsPage-CitZ6FAS.js} +1 -1
- package/assets/assets/{SiteHealthSection-FF14aIXT.js → SiteHealthSection-C2dsyNGY.js} +3 -3
- package/assets/assets/{TrafficPage-C_qoeGDl.js → TrafficPage-lY8na5Pg.js} +1 -1
- package/assets/assets/{TrafficSourceDetailPage-B3i_B2MI.js → TrafficSourceDetailPage-BTykoVGT.js} +1 -1
- package/assets/assets/{extract-error-message-BisUn6nN.js → extract-error-message-r0Gpc7mv.js} +1 -1
- package/assets/assets/{index-Dht7JNX5.js → index-DwlO8KfE.js} +21 -21
- package/assets/assets/{react-sigma_core.esm.min-tWhS09SS.js → react-sigma_core.esm.min-DDrDxbO1.js} +1 -1
- package/assets/assets/{v2-overview-adapter-CAoeWKQJ.js → v2-overview-adapter-OsQiglXU.js} +1 -1
- package/assets/index.html +1 -1
- package/dist/{chunk-TWLJRAWA.js → chunk-3LCR6WU6.js} +2 -2
- package/dist/{chunk-JJPZ4OQ2.js → chunk-DDL2XSNM.js} +8 -4
- package/dist/{chunk-PXVJ3P5G.js → chunk-GLLY2GEV.js} +8 -5
- package/dist/{chunk-NSKFW3NF.js → chunk-P5VXVFQW.js} +1095 -457
- package/dist/{chunk-TOSPZ7I5.js → chunk-S5OSY3PI.js} +78 -5
- package/dist/{chunk-P73YBGZP.js → chunk-XFHXKLNT.js} +23 -12
- package/dist/{chunk-CVUR3O5G.js → chunk-YTSXQUJ3.js} +3 -3
- package/dist/cli.js +76 -16
- package/dist/{demo-server-FH2K6TCD.js → demo-server-HULNEORN.js} +4 -4
- package/dist/index.js +6 -6
- package/dist/{intelligence-service-QHSR2H7F.js → intelligence-service-CXNBKRHV.js} +2 -2
- package/dist/mcp.js +4 -4
- package/package.json +12 -12
|
@@ -13572,7 +13572,7 @@ var visibilityCompareVerdictSchema = z41.enum([
|
|
|
13572
13572
|
var visibilityCompareDirectionSchema = z41.enum(["up", "down", "flat"]);
|
|
13573
13573
|
var visibilityCompareMetricPeriodSchema = z41.object({
|
|
13574
13574
|
/** Why this period can or cannot produce a proportion. Raw numerator counts remain visible when the frame is missing. */
|
|
13575
|
-
availability: z41.enum(["available", "no-observations", "no-competitive-frame"]),
|
|
13575
|
+
availability: z41.enum(["available", "no-observations", "no-competitive-frame", "classification-unavailable"]),
|
|
13576
13576
|
/** The proportion in `[0,1]`, rounded to 4 dp; `null` when `denominator === 0` (undefined over no data). */
|
|
13577
13577
|
point: z41.number().nullable(),
|
|
13578
13578
|
/** Wilson 95% lower bound `[0,1]`; `null` when `denominator === 0`. */
|
|
@@ -13582,14 +13582,34 @@ var visibilityCompareMetricPeriodSchema = z41.object({
|
|
|
13582
13582
|
/** Successes (mentions / citations / project-brand mentions), preserved even when the competitive frame is unavailable. */
|
|
13583
13583
|
numerator: z41.number().int(),
|
|
13584
13584
|
/** Sample size the proportion is over (checked snapshots / total / project+competitor brand mentions). */
|
|
13585
|
-
denominator: z41.number().int()
|
|
13585
|
+
denominator: z41.number().int(),
|
|
13586
|
+
/**
|
|
13587
|
+
* Observations missing this metric's own signal, excluded from its
|
|
13588
|
+
* denominator: an unknown mention for a class mention rate, incomplete
|
|
13589
|
+
* source capture for a class cited rate, and, on frames that record capture
|
|
13590
|
+
* completeness (Advanced), for the pooled cited rate and cited share of voice.
|
|
13591
|
+
*/
|
|
13592
|
+
excludedUnknown: z41.number().int().nonnegative().optional()
|
|
13586
13593
|
});
|
|
13587
13594
|
var visibilityCompareMetricKeySchema = z41.enum([
|
|
13588
13595
|
"mention-share-of-voice",
|
|
13589
13596
|
"cited-share-of-voice",
|
|
13590
13597
|
"mention-rate",
|
|
13591
|
-
"cited-rate"
|
|
13598
|
+
"cited-rate",
|
|
13599
|
+
"mention-rate-branded",
|
|
13600
|
+
"cited-rate-branded",
|
|
13601
|
+
"mention-rate-non-brand",
|
|
13602
|
+
"cited-rate-non-brand"
|
|
13592
13603
|
]);
|
|
13604
|
+
var VISIBILITY_COMPARE_CLASS_METRIC_KEYS = [
|
|
13605
|
+
"mention-rate-branded",
|
|
13606
|
+
"cited-rate-branded",
|
|
13607
|
+
"mention-rate-non-brand",
|
|
13608
|
+
"cited-rate-non-brand"
|
|
13609
|
+
];
|
|
13610
|
+
function isVisibilityCompareClassMetric(key) {
|
|
13611
|
+
return VISIBILITY_COMPARE_CLASS_METRIC_KEYS.includes(key);
|
|
13612
|
+
}
|
|
13593
13613
|
var visibilityCompareMetricSchema = z41.object({
|
|
13594
13614
|
key: visibilityCompareMetricKeySchema,
|
|
13595
13615
|
/** Human label ("Named share of voice", "Cited rate", …). */
|
|
@@ -13598,7 +13618,7 @@ var visibilityCompareMetricSchema = z41.object({
|
|
|
13598
13618
|
* Query class behind this metric. `all` is an intentional all-query rate;
|
|
13599
13619
|
* `pooled` means no usable project identity existed for the requested split.
|
|
13600
13620
|
*/
|
|
13601
|
-
queryClass: z41.enum(["all", "non-brand", "pooled"]),
|
|
13621
|
+
queryClass: z41.enum(["all", "branded", "non-brand", "pooled"]),
|
|
13602
13622
|
/**
|
|
13603
13623
|
* `true` for share of voice, which is less exposed to broad model-wide naming
|
|
13604
13624
|
* propensity than an absolute rate. It does not bypass model continuity: no
|
|
@@ -13681,12 +13701,33 @@ var visibilityCompareQueriesMentionedSchema = z41.object({
|
|
|
13681
13701
|
from: z41.object({ count: z41.number().int(), of: z41.number().int() }),
|
|
13682
13702
|
to: z41.object({ count: z41.number().int(), of: z41.number().int() })
|
|
13683
13703
|
});
|
|
13704
|
+
var visibilityCompareSelectionSchema = z41.object({
|
|
13705
|
+
scope: z41.enum(["project", "group", "market", "property"]).optional(),
|
|
13706
|
+
scopeKey: z41.string().min(1).optional(),
|
|
13707
|
+
marketKey: z41.string().min(1).optional(),
|
|
13708
|
+
provider: z41.string().min(1).optional(),
|
|
13709
|
+
location: z41.string().min(1).optional()
|
|
13710
|
+
});
|
|
13711
|
+
var visibilityCompareClassComparisonSchema = z41.object({
|
|
13712
|
+
from: visibilityComparePeriodWindowSchema,
|
|
13713
|
+
to: visibilityComparePeriodWindowSchema,
|
|
13714
|
+
basket: visibilityCompareBasketSchema,
|
|
13715
|
+
continuity: visibilityCompareContinuitySchema,
|
|
13716
|
+
modelChanges: z41.array(visibilityCompareModelChangeSchema)
|
|
13717
|
+
});
|
|
13684
13718
|
var visibilityCompareDtoSchema = z41.object({
|
|
13685
13719
|
project: z41.string(),
|
|
13720
|
+
selection: visibilityCompareSelectionSchema.optional(),
|
|
13721
|
+
/** Frozen Advanced cohort used by the additive class metrics; legacy project metrics retain their original frame. */
|
|
13722
|
+
classComparison: visibilityCompareClassComparisonSchema.optional(),
|
|
13686
13723
|
from: visibilityComparePeriodWindowSchema,
|
|
13687
13724
|
to: visibilityComparePeriodWindowSchema,
|
|
13688
13725
|
basket: visibilityCompareBasketSchema,
|
|
13689
|
-
/**
|
|
13726
|
+
/**
|
|
13727
|
+
* Ordered: mention SoV (primary), cited SoV, mention rate (level), cited rate,
|
|
13728
|
+
* then the class rates (`mention-rate-branded`, `cited-rate-branded`,
|
|
13729
|
+
* `mention-rate-non-brand`, `cited-rate-non-brand`). Read metrics by `key`.
|
|
13730
|
+
*/
|
|
13690
13731
|
metrics: z41.array(visibilityCompareMetricSchema),
|
|
13691
13732
|
queriesMentioned: visibilityCompareQueriesMentionedSchema,
|
|
13692
13733
|
byProvider: z41.array(visibilityCompareProviderRowSchema),
|
|
@@ -15010,12 +15051,27 @@ var checkCategorySchema = z50.enum([
|
|
|
15010
15051
|
"agent"
|
|
15011
15052
|
]);
|
|
15012
15053
|
var CheckCategories = checkCategorySchema.enum;
|
|
15054
|
+
var checkNotificationPolicySchema = z50.enum(["health", "silent"]);
|
|
15055
|
+
var CheckNotificationPolicies = checkNotificationPolicySchema.enum;
|
|
15056
|
+
var reportMonthSchema = z50.string().regex(/^[1-9]\d{3}-(0[1-9]|1[0-2])$/, "Expected YYYY-MM");
|
|
15057
|
+
function reportMonthsForDoctor(reportMonth, now = /* @__PURE__ */ new Date()) {
|
|
15058
|
+
if (reportMonth !== void 0) return [reportMonthSchema.parse(reportMonth)];
|
|
15059
|
+
const current = now.toISOString().slice(0, 7);
|
|
15060
|
+
if (now.getUTCDate() > 3) return [current];
|
|
15061
|
+
const previous = new Date(Date.parse(calendarMonthBounds(current).since) - 1).toISOString().slice(0, 7);
|
|
15062
|
+
return [previous, current];
|
|
15063
|
+
}
|
|
15064
|
+
function gradedReportMonths(months, now = /* @__PURE__ */ new Date()) {
|
|
15065
|
+
const current = now.toISOString().slice(0, 7);
|
|
15066
|
+
return new Set(months.length > 1 ? months.filter((month) => month !== current) : months);
|
|
15067
|
+
}
|
|
15013
15068
|
var checkResultSchema = z50.object({
|
|
15014
15069
|
id: z50.string(),
|
|
15015
15070
|
category: checkCategorySchema,
|
|
15016
15071
|
scope: checkScopeSchema,
|
|
15017
15072
|
title: z50.string(),
|
|
15018
15073
|
status: checkStatusSchema,
|
|
15074
|
+
notificationPolicy: checkNotificationPolicySchema.optional().describe("Health checks page by default. Silent report advisories remain visible but never affect health alert state."),
|
|
15019
15075
|
code: z50.string().describe('Stable machine-readable code (e.g. "google.token.refresh-failed"). Use this for filtering and remediation logic.'),
|
|
15020
15076
|
summary: z50.string(),
|
|
15021
15077
|
remediation: z50.string().nullable().optional().describe('Operator-facing next step. Null when status is "ok" or no specific remediation applies.'),
|
|
@@ -15025,6 +15081,7 @@ var checkResultSchema = z50.object({
|
|
|
15025
15081
|
var doctorReportSchema = z50.object({
|
|
15026
15082
|
scope: checkScopeSchema,
|
|
15027
15083
|
project: z50.string().nullable().describe('Project name when scope is "project", null otherwise.'),
|
|
15084
|
+
reportMonths: z50.array(reportMonthSchema).optional().describe("Calendar months evaluated by project report readiness checks."),
|
|
15028
15085
|
generatedAt: z50.string().describe("ISO-8601 timestamp when this doctor run started."),
|
|
15029
15086
|
durationMs: z50.number().int().nonnegative(),
|
|
15030
15087
|
summary: z50.object({
|
|
@@ -15056,6 +15113,15 @@ function summarizeCheckResults(results) {
|
|
|
15056
15113
|
}
|
|
15057
15114
|
return summary;
|
|
15058
15115
|
}
|
|
15116
|
+
function groupIsoDateRanges(dates) {
|
|
15117
|
+
const ranges = [];
|
|
15118
|
+
for (const date of [...new Set(dates)].sort()) {
|
|
15119
|
+
const previous = ranges.at(-1);
|
|
15120
|
+
if (previous && shiftIsoCalendarDate(previous.end, 1) === date) previous.end = date;
|
|
15121
|
+
else ranges.push({ start: date, end: date });
|
|
15122
|
+
}
|
|
15123
|
+
return ranges;
|
|
15124
|
+
}
|
|
15059
15125
|
|
|
15060
15126
|
// ../contracts/src/index-coverage.ts
|
|
15061
15127
|
function deriveIndexCoverage(input) {
|
|
@@ -20115,6 +20181,8 @@ export {
|
|
|
20115
20181
|
windowCutoff,
|
|
20116
20182
|
resolveDateRange,
|
|
20117
20183
|
visibilityStatsDtoSchema,
|
|
20184
|
+
isVisibilityCompareClassMetric,
|
|
20185
|
+
visibilityCompareSelectionSchema,
|
|
20118
20186
|
visibilityCompareDtoSchema,
|
|
20119
20187
|
calendarMonthBounds,
|
|
20120
20188
|
resultsExportDtoSchema,
|
|
@@ -20186,8 +20254,13 @@ export {
|
|
|
20186
20254
|
CheckStatuses,
|
|
20187
20255
|
CheckScopes,
|
|
20188
20256
|
CheckCategories,
|
|
20257
|
+
CheckNotificationPolicies,
|
|
20258
|
+
reportMonthSchema,
|
|
20259
|
+
reportMonthsForDoctor,
|
|
20260
|
+
gradedReportMonths,
|
|
20189
20261
|
doctorReportSchema,
|
|
20190
20262
|
summarizeCheckResults,
|
|
20263
|
+
groupIsoDateRanges,
|
|
20191
20264
|
deriveIndexCoverage,
|
|
20192
20265
|
normalizeQueryText,
|
|
20193
20266
|
citationVisibilityResponseSchema,
|
|
@@ -13,19 +13,19 @@ import {
|
|
|
13
13
|
resolveOperatorApiKeyIds,
|
|
14
14
|
runWithUsageTags,
|
|
15
15
|
saveConfigPatch
|
|
16
|
-
} from "./chunk-
|
|
16
|
+
} from "./chunk-GLLY2GEV.js";
|
|
17
17
|
import {
|
|
18
18
|
deleteSiteCrawlGraphLayout,
|
|
19
19
|
persistSiteCrawlGraphLayout,
|
|
20
20
|
prepareSiteCrawlGraphLayout
|
|
21
|
-
} from "./chunk-
|
|
21
|
+
} from "./chunk-3LCR6WU6.js";
|
|
22
22
|
import {
|
|
23
23
|
CanonryMcpToolNames,
|
|
24
24
|
CliError,
|
|
25
25
|
PACKAGE_VERSION,
|
|
26
26
|
canonryMcpTools,
|
|
27
27
|
isMachineFormat
|
|
28
|
-
} from "./chunk-
|
|
28
|
+
} from "./chunk-DDL2XSNM.js";
|
|
29
29
|
import {
|
|
30
30
|
CC_CACHE_DIR,
|
|
31
31
|
DUCKDB_SPEC,
|
|
@@ -172,6 +172,7 @@ import {
|
|
|
172
172
|
runChecks,
|
|
173
173
|
runFills,
|
|
174
174
|
runs,
|
|
175
|
+
scheduledHealthCheckIds,
|
|
175
176
|
schedules,
|
|
176
177
|
serializeUserSessionCookie,
|
|
177
178
|
siteAuditPages,
|
|
@@ -186,7 +187,7 @@ import {
|
|
|
186
187
|
siteLivenessState,
|
|
187
188
|
toAlertView,
|
|
188
189
|
usageCounters
|
|
189
|
-
} from "./chunk-
|
|
190
|
+
} from "./chunk-P5VXVFQW.js";
|
|
190
191
|
import {
|
|
191
192
|
AGENT_MEMORY_VALUE_MAX_BYTES,
|
|
192
193
|
AGENT_NONE,
|
|
@@ -201,6 +202,7 @@ import {
|
|
|
201
202
|
CANONRY_NPM_PACKAGE_URL,
|
|
202
203
|
CITED_URL_CAPTURE_VERSION,
|
|
203
204
|
CcReleaseSyncStatuses,
|
|
205
|
+
CheckNotificationPolicies,
|
|
204
206
|
DEFAULT_VIEWER_RESEARCH_DAILY_RUN_LIMIT,
|
|
205
207
|
DiscoveryCompetitorTypes,
|
|
206
208
|
GOOGLE_ADS_CAMPAIGN_METRICS_MAX_CAMPAIGNS,
|
|
@@ -303,6 +305,7 @@ import {
|
|
|
303
305
|
hostMatchesAnyDomain,
|
|
304
306
|
hostMatchesDomain,
|
|
305
307
|
hostOf,
|
|
308
|
+
inclusiveDayCount,
|
|
306
309
|
isAgentProviderId,
|
|
307
310
|
isBrowserProvider,
|
|
308
311
|
isGhostTelemetryEvent,
|
|
@@ -331,6 +334,7 @@ import {
|
|
|
331
334
|
providerError,
|
|
332
335
|
providerSupportsLocationContext,
|
|
333
336
|
registrableDomain,
|
|
337
|
+
reportMonthsForDoctor,
|
|
334
338
|
resolveProviderModel,
|
|
335
339
|
resolveSnapshotRequestQueries,
|
|
336
340
|
retryAfterDelayMs,
|
|
@@ -353,7 +357,7 @@ import {
|
|
|
353
357
|
visibilityReportRequestSchema,
|
|
354
358
|
winnabilityClassLabel,
|
|
355
359
|
withRetry
|
|
356
|
-
} from "./chunk-
|
|
360
|
+
} from "./chunk-S5OSY3PI.js";
|
|
357
361
|
|
|
358
362
|
// src/runtime-context.ts
|
|
359
363
|
function cliRuntimeContext(env = process.env, stdio = process) {
|
|
@@ -6648,7 +6652,7 @@ function nonBlank(value) {
|
|
|
6648
6652
|
return trimmed ? trimmed : void 0;
|
|
6649
6653
|
}
|
|
6650
6654
|
function resolveBuildCommit(env = process.env) {
|
|
6651
|
-
const embedded = true ? "
|
|
6655
|
+
const embedded = true ? "120bbd89c1dedb8df5c2850da43ac2e71ccd3cdc" : void 0;
|
|
6652
6656
|
return nonBlank(embedded) ?? nonBlank(env.CANONRY_COMMIT);
|
|
6653
6657
|
}
|
|
6654
6658
|
function resolveInstanceIdentity(env = process.env) {
|
|
@@ -12235,7 +12239,7 @@ function readStoredGroundingSources(rawResponse) {
|
|
|
12235
12239
|
return result2;
|
|
12236
12240
|
}
|
|
12237
12241
|
async function backfillInsightsCommand(project, opts) {
|
|
12238
|
-
const { IntelligenceService: IntelligenceService2 } = await import("./intelligence-service-
|
|
12242
|
+
const { IntelligenceService: IntelligenceService2 } = await import("./intelligence-service-CXNBKRHV.js");
|
|
12239
12243
|
const config = loadConfig();
|
|
12240
12244
|
const db = createClient(config.database);
|
|
12241
12245
|
migrate(db);
|
|
@@ -13436,11 +13440,16 @@ function startSiteLivenessLoop(deps, intervalMs = SITE_LIVENESS_INTERVAL_MS) {
|
|
|
13436
13440
|
|
|
13437
13441
|
// src/data-refresh.ts
|
|
13438
13442
|
var log16 = createLogger("DataRefresh");
|
|
13439
|
-
|
|
13443
|
+
function gaRefreshDays(now = /* @__PURE__ */ new Date()) {
|
|
13444
|
+
const [reportMonth] = reportMonthsForDoctor(void 0, now);
|
|
13445
|
+
const reach = inclusiveDayCount(`${reportMonth}-01`, now.toISOString().slice(0, 10)) ?? 0;
|
|
13446
|
+
return Math.max(30, reach);
|
|
13447
|
+
}
|
|
13448
|
+
async function refreshAllIntegrations(client, projectName, now = /* @__PURE__ */ new Date()) {
|
|
13440
13449
|
const integrations = [
|
|
13441
13450
|
{ name: "gsc", run: () => client.gscSync(projectName, {}) },
|
|
13442
13451
|
{ name: "bing", run: () => client.bingInspectSitemap(projectName, {}) },
|
|
13443
|
-
{ name: "ga", run: () => client.gaSync(projectName, { days:
|
|
13452
|
+
{ name: "ga", run: () => client.gaSync(projectName, { days: gaRefreshDays(now) }) },
|
|
13444
13453
|
{ name: "gbp", run: () => client.triggerGbpSync(projectName, {}) },
|
|
13445
13454
|
// `ads` remains the OpenAI / ChatGPT Ads integration. For scheduled
|
|
13446
13455
|
// refreshes, Google providers have explicit names and fan out only here.
|
|
@@ -13581,13 +13590,15 @@ var Notifier = class {
|
|
|
13581
13590
|
return 0;
|
|
13582
13591
|
}
|
|
13583
13592
|
};
|
|
13584
|
-
const
|
|
13593
|
+
const healthChecks = report.checks.filter((c) => c.notificationPolicy !== CheckNotificationPolicies.silent);
|
|
13594
|
+
if (healthChecks.length === 0 && report.checks.length > 0) return null;
|
|
13595
|
+
const graded = healthChecks.filter((c) => c.status === "fail" || c.status === "warn" || c.status === "ok");
|
|
13585
13596
|
const failing = graded.filter((c) => c.status !== "ok").sort((a, b) => rank(b.status) - rank(a.status) || categoryRank(b.category) - categoryRank(a.category) || a.id.localeCompare(b.id));
|
|
13586
13597
|
const worst = failing.at(0) ?? null;
|
|
13587
13598
|
const noSignal = graded.length === 0;
|
|
13588
13599
|
const status = noSignal ? "warn" : worst ? worst.status : "ok";
|
|
13589
13600
|
const code = noSignal ? "health.no-signal" : worst?.code ?? "health.ok";
|
|
13590
|
-
const summary = noSignal ? `No health check produced a result (${
|
|
13601
|
+
const summary = noSignal ? `No health check produced a result (${healthChecks.length} skipped) \u2014 health is unknown, not confirmed.` : worst?.summary ?? `All ${graded.length} health check(s) passing.`;
|
|
13591
13602
|
const previous = this.db.select().from(doctorHealthState).where(eq17(doctorHealthState.projectId, projectId)).get();
|
|
13592
13603
|
const previousStatus = previous?.status ?? null;
|
|
13593
13604
|
const failingSignature = failing.map((c) => `${c.status}:${c.code}`).join(",");
|
|
@@ -19493,7 +19504,7 @@ async function createServer(opts) {
|
|
|
19493
19504
|
onDoctorRequested: (projectName) => {
|
|
19494
19505
|
void (async () => {
|
|
19495
19506
|
try {
|
|
19496
|
-
const report = await schedulerClient.runDoctor({ project: projectName });
|
|
19507
|
+
const report = await schedulerClient.runDoctor({ project: projectName, checkIds: scheduledHealthCheckIds() });
|
|
19497
19508
|
const project = opts.db.select().from(projects).where(eq27(projects.name, projectName)).get();
|
|
19498
19509
|
if (!project) {
|
|
19499
19510
|
app.log.warn({ projectName }, "doctor schedule fired for an unknown project");
|
|
@@ -4,14 +4,14 @@ import {
|
|
|
4
4
|
installSkills,
|
|
5
5
|
loadConfigRaw,
|
|
6
6
|
saveConfigPatch
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-GLLY2GEV.js";
|
|
8
8
|
import {
|
|
9
9
|
PACKAGE_VERSION
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-DDL2XSNM.js";
|
|
11
11
|
import {
|
|
12
12
|
SKILL_MANIFEST_FILENAME,
|
|
13
13
|
SkillsClients
|
|
14
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-S5OSY3PI.js";
|
|
15
15
|
|
|
16
16
|
// src/skills-autosync.ts
|
|
17
17
|
import fs from "fs";
|
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-XFHXKLNT.js";
|
|
39
39
|
import {
|
|
40
40
|
autoSyncSkills,
|
|
41
41
|
formatAutoSyncNotice
|
|
42
|
-
} from "./chunk-
|
|
42
|
+
} from "./chunk-YTSXQUJ3.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-GLLY2GEV.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-3LCR6WU6.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-DDL2XSNM.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-P5VXVFQW.js";
|
|
93
93
|
import {
|
|
94
94
|
AdsDeliverySnapshotStatuses,
|
|
95
95
|
AdsHistoricalCampaignRollupStatuses,
|
|
@@ -146,6 +146,7 @@ import {
|
|
|
146
146
|
formatRunErrorOneLine,
|
|
147
147
|
formatWholePercent,
|
|
148
148
|
googleAdsMetricsWindowSchema,
|
|
149
|
+
isVisibilityCompareClassMetric,
|
|
149
150
|
logQuerySchema,
|
|
150
151
|
measurementChangesQuerySchema,
|
|
151
152
|
measurementDataQualityQuerySchema,
|
|
@@ -175,9 +176,10 @@ import {
|
|
|
175
176
|
shareOfVoiceLabel,
|
|
176
177
|
shareOfVoiceReason,
|
|
177
178
|
snapshotProviderModeSchema,
|
|
179
|
+
visibilityCompareSelectionSchema,
|
|
178
180
|
visibilityReportRequestSchema,
|
|
179
181
|
winnabilityClassSchema
|
|
180
|
-
} from "./chunk-
|
|
182
|
+
} from "./chunk-S5OSY3PI.js";
|
|
181
183
|
|
|
182
184
|
// src/cli.ts
|
|
183
185
|
import { pathToFileURL } from "url";
|
|
@@ -442,7 +444,7 @@ function parseDemoTrustedProxies(values) {
|
|
|
442
444
|
async function demoCommand(options) {
|
|
443
445
|
const { host, port } = parseDemoListenOptions(options);
|
|
444
446
|
const trustProxy = parseDemoTrustedProxies(options.trustProxy);
|
|
445
|
-
const { createDemoServer } = await import("./demo-server-
|
|
447
|
+
const { createDemoServer } = await import("./demo-server-HULNEORN.js");
|
|
446
448
|
const app = await createDemoServer({ trustProxy });
|
|
447
449
|
let stopping = false;
|
|
448
450
|
const stop = () => {
|
|
@@ -3049,7 +3051,8 @@ async function doctorCommand(opts) {
|
|
|
3049
3051
|
const client = createApiClient();
|
|
3050
3052
|
const report = await client.runDoctor({
|
|
3051
3053
|
project: opts.project,
|
|
3052
|
-
checkIds: opts.checks
|
|
3054
|
+
checkIds: opts.checks,
|
|
3055
|
+
...opts.reportMonth ? { reportMonth: opts.reportMonth } : {}
|
|
3053
3056
|
});
|
|
3054
3057
|
if (opts.format === "json") {
|
|
3055
3058
|
console.log(JSON.stringify(report, null, 2));
|
|
@@ -3075,8 +3078,8 @@ async function runDoctorAll(opts) {
|
|
|
3075
3078
|
const client = createApiClient();
|
|
3076
3079
|
const projects2 = await client.listProjects();
|
|
3077
3080
|
const [globalReport, ...projectReports] = await Promise.all([
|
|
3078
|
-
client.runDoctor({ checkIds: opts.checks }),
|
|
3079
|
-
...projects2.map((p) => client.runDoctor({ project: p.name, checkIds: opts.checks }))
|
|
3081
|
+
client.runDoctor({ checkIds: opts.checks, ...opts.reportMonth ? { reportMonth: opts.reportMonth } : {} }),
|
|
3082
|
+
...projects2.map((p) => client.runDoctor({ project: p.name, checkIds: opts.checks, ...opts.reportMonth ? { reportMonth: opts.reportMonth } : {} }))
|
|
3080
3083
|
]);
|
|
3081
3084
|
const byKey = { __global__: globalReport };
|
|
3082
3085
|
projects2.forEach((p, i) => {
|
|
@@ -3172,13 +3175,14 @@ ${header}`);
|
|
|
3172
3175
|
}
|
|
3173
3176
|
|
|
3174
3177
|
// src/cli-commands/doctor.ts
|
|
3175
|
-
var USAGE = "canonry doctor [--project <name>|--all] [--check <id>...] [--format json|jsonl]";
|
|
3178
|
+
var USAGE = "canonry doctor [--project <name>|--all] [--check <id>...] [--report-month YYYY-MM] [--format json|jsonl]";
|
|
3176
3179
|
var DOCTOR_CLI_COMMANDS = [
|
|
3177
3180
|
{
|
|
3178
3181
|
path: ["doctor"],
|
|
3179
3182
|
usage: USAGE,
|
|
3180
3183
|
options: {
|
|
3181
3184
|
project: stringOption(),
|
|
3185
|
+
"report-month": stringOption(),
|
|
3182
3186
|
check: multiStringOption(),
|
|
3183
3187
|
all: { type: "boolean" }
|
|
3184
3188
|
},
|
|
@@ -3186,6 +3190,7 @@ var DOCTOR_CLI_COMMANDS = [
|
|
|
3186
3190
|
run: async (input) => {
|
|
3187
3191
|
await doctorCommand({
|
|
3188
3192
|
project: getString(input.values, "project"),
|
|
3193
|
+
reportMonth: getString(input.values, "report-month"),
|
|
3189
3194
|
all: getBoolean(input.values, "all"),
|
|
3190
3195
|
checks: getStringArray(input.values, "check"),
|
|
3191
3196
|
format: input.format
|
|
@@ -17420,7 +17425,7 @@ function pct3(rate) {
|
|
|
17420
17425
|
async function showVisibilityCompare(project, opts) {
|
|
17421
17426
|
if (!opts.from || !opts.to) throw new Error("visibility-compare requires --from <YYYY-MM> and --to <YYYY-MM>");
|
|
17422
17427
|
const client = createApiClient();
|
|
17423
|
-
const data = await client.getVisibilityCompare(project, opts.from, opts.to);
|
|
17428
|
+
const data = await client.getVisibilityCompare(project, opts.from, opts.to, { scope: opts.scope, scopeKey: opts.scopeKey, marketKey: opts.marketKey, provider: opts.provider, location: opts.location });
|
|
17424
17429
|
if (isMachineFormat(opts.format)) {
|
|
17425
17430
|
console.log(JSON.stringify(data, null, 2));
|
|
17426
17431
|
return;
|
|
@@ -17428,6 +17433,7 @@ async function showVisibilityCompare(project, opts) {
|
|
|
17428
17433
|
printVisibilityCompare(data);
|
|
17429
17434
|
}
|
|
17430
17435
|
function periodCell(p) {
|
|
17436
|
+
if (p.availability === "classification-unavailable") return "unavailable: query classification";
|
|
17431
17437
|
if (p.availability === "no-competitive-frame") {
|
|
17432
17438
|
return `unavailable: no competitive frame (${p.numerator} observed)`;
|
|
17433
17439
|
}
|
|
@@ -17450,12 +17456,24 @@ function verdictCell(m) {
|
|
|
17450
17456
|
}
|
|
17451
17457
|
}
|
|
17452
17458
|
function metricQueryClassLabel(metric) {
|
|
17459
|
+
if (metric.queryClass === "branded") return "branded queries";
|
|
17453
17460
|
if (metric.queryClass === "non-brand") return "non-brand queries";
|
|
17454
17461
|
if (metric.queryClass === "pooled") return "pooled queries; classification unavailable";
|
|
17455
17462
|
return "all queries";
|
|
17456
17463
|
}
|
|
17464
|
+
function selectionLabel(selection) {
|
|
17465
|
+
if (!selection) return null;
|
|
17466
|
+
const parts = [];
|
|
17467
|
+
if (selection.scope && selection.scope !== "project") parts.push(`${selection.scope} ${selection.scopeKey ?? ""}`.trim());
|
|
17468
|
+
if (selection.marketKey) parts.push(`market ${selection.marketKey}`);
|
|
17469
|
+
if (selection.provider) parts.push(`engine ${selection.provider}`);
|
|
17470
|
+
if (selection.location) parts.push(`location ${selection.location}`);
|
|
17471
|
+
return parts.length > 0 ? parts.join(" \xB7 ") : null;
|
|
17472
|
+
}
|
|
17457
17473
|
function printVisibilityCompare(data) {
|
|
17458
17474
|
console.log(`AEO month over month: ${data.project} ${data.from.month} -> ${data.to.month}`);
|
|
17475
|
+
const selection = selectionLabel(data.selection);
|
|
17476
|
+
if (selection) console.log(`Selection: ${selection}`);
|
|
17459
17477
|
const b = data.basket;
|
|
17460
17478
|
const excl = [];
|
|
17461
17479
|
if (b.excludedFromOnly > 0) excl.push(`${b.excludedFromOnly} only in ${data.from.month}`);
|
|
@@ -17469,8 +17487,19 @@ function printVisibilityCompare(data) {
|
|
|
17469
17487
|
console.log(`Continuity: ${data.continuity.status.replace("-", " ")} \u2014 no directional call is made.`);
|
|
17470
17488
|
}
|
|
17471
17489
|
console.log("");
|
|
17490
|
+
if (data.classComparison) {
|
|
17491
|
+
const frame = data.classComparison;
|
|
17492
|
+
console.log(`Class metrics basket (frozen Advanced): ${frame.basket.queryCount} queries; engines: ${frame.basket.providers.join(", ") || "none"}`);
|
|
17493
|
+
const classSweeps = `Class basket sweeps: ${frame.from.month} ${frame.from.runCount}, ${frame.to.month} ${frame.to.runCount}; continuity: ${frame.continuity.status}`;
|
|
17494
|
+
const classLow = frame.from.lowRunCount || frame.to.lowRunCount;
|
|
17495
|
+
console.log(classLow ? `${classSweeps} (below the 5-sweep floor \u2014 class intervals are wide, a "moved" verdict is unlikely to be reachable)` : classSweeps);
|
|
17496
|
+
for (const provider of frame.continuity.providers) {
|
|
17497
|
+
if (provider.status !== "included") console.log(`Class basket excludes ${provider.provider}: ${provider.fromModels.join("/") || "?"} -> ${provider.toModels.join("/") || "?"} (${provider.status})`);
|
|
17498
|
+
}
|
|
17499
|
+
console.log("");
|
|
17500
|
+
}
|
|
17472
17501
|
const rows = data.metrics.map((m) => ({
|
|
17473
|
-
label: `${m.label} \xB7 ${metricQueryClassLabel(m)}${m.driftRobust ? " *" : ""}`,
|
|
17502
|
+
label: `${m.label} \xB7 ${metricQueryClassLabel(m)}${data.classComparison && isVisibilityCompareClassMetric(m.key) ? " \xB7 class basket" : ""}${m.driftRobust ? " *" : ""}`,
|
|
17474
17503
|
to: periodCell(m.to),
|
|
17475
17504
|
from: periodCell(m.from),
|
|
17476
17505
|
verdict: verdictCell(m)
|
|
@@ -17600,7 +17629,32 @@ function parseQueryClass(value) {
|
|
|
17600
17629
|
}
|
|
17601
17630
|
return value;
|
|
17602
17631
|
}
|
|
17603
|
-
var COMPARE_USAGE = "canonry visibility-compare <project> --from <YYYY-MM> --to <YYYY-MM> [--format json]";
|
|
17632
|
+
var COMPARE_USAGE = "canonry visibility-compare <project> --from <YYYY-MM> --to <YYYY-MM> [--scope project|group|market|property] [--scope-key <key>] [--market-key <key>] [--provider <engine>] [--location <label|none>] [--format json]";
|
|
17633
|
+
var COMPARE_SELECTION_FLAGS = {
|
|
17634
|
+
scope: "--scope",
|
|
17635
|
+
scopeKey: "--scope-key",
|
|
17636
|
+
marketKey: "--market-key",
|
|
17637
|
+
provider: "--provider",
|
|
17638
|
+
location: "--location"
|
|
17639
|
+
};
|
|
17640
|
+
function parseCompareSelection(values) {
|
|
17641
|
+
const parsed = visibilityCompareSelectionSchema.safeParse({
|
|
17642
|
+
scope: getString(values, "scope"),
|
|
17643
|
+
scopeKey: getString(values, "scope-key"),
|
|
17644
|
+
marketKey: getString(values, "market-key"),
|
|
17645
|
+
provider: getString(values, "provider"),
|
|
17646
|
+
location: getString(values, "location")
|
|
17647
|
+
});
|
|
17648
|
+
if (parsed.success) return parsed.data;
|
|
17649
|
+
const issue = parsed.error.issues[0];
|
|
17650
|
+
const flag = COMPARE_SELECTION_FLAGS[String(issue.path[0])] ?? "--scope";
|
|
17651
|
+
const message = flag === "--scope" ? "--scope must be one of: project, group, market, property" : `${flag} must not be empty`;
|
|
17652
|
+
throw usageError(`Error: ${message}
|
|
17653
|
+
Usage: ${COMPARE_USAGE}`, {
|
|
17654
|
+
message,
|
|
17655
|
+
details: { command: "visibility-compare", usage: COMPARE_USAGE }
|
|
17656
|
+
});
|
|
17657
|
+
}
|
|
17604
17658
|
var VISIBILITY_STATS_CLI_COMMANDS = [
|
|
17605
17659
|
{
|
|
17606
17660
|
path: ["visibility-stats"],
|
|
@@ -17637,13 +17691,19 @@ var VISIBILITY_STATS_CLI_COMMANDS = [
|
|
|
17637
17691
|
usage: COMPARE_USAGE,
|
|
17638
17692
|
options: {
|
|
17639
17693
|
from: stringOption(),
|
|
17640
|
-
to: stringOption()
|
|
17694
|
+
to: stringOption(),
|
|
17695
|
+
scope: stringOption(),
|
|
17696
|
+
"scope-key": stringOption(),
|
|
17697
|
+
"market-key": stringOption(),
|
|
17698
|
+
provider: stringOption(),
|
|
17699
|
+
location: stringOption()
|
|
17641
17700
|
},
|
|
17642
17701
|
run: async (input) => {
|
|
17643
17702
|
const project = requireProject(input, "visibility-compare", COMPARE_USAGE);
|
|
17644
17703
|
await showVisibilityCompare(project, {
|
|
17645
17704
|
from: getString(input.values, "from"),
|
|
17646
17705
|
to: getString(input.values, "to"),
|
|
17706
|
+
...parseCompareSelection(input.values),
|
|
17647
17707
|
format: input.format
|
|
17648
17708
|
});
|
|
17649
17709
|
}
|
|
@@ -4,11 +4,11 @@ import {
|
|
|
4
4
|
import {
|
|
5
5
|
layoutSiteCrawlGraphInput,
|
|
6
6
|
persistSiteCrawlGraphLayout
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-3LCR6WU6.js";
|
|
8
8
|
import {
|
|
9
9
|
PACKAGE_VERSION,
|
|
10
10
|
canonryMcpTools
|
|
11
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-DDL2XSNM.js";
|
|
12
12
|
import {
|
|
13
13
|
HISTORY_WINDOW_RUNS,
|
|
14
14
|
IntelligenceService,
|
|
@@ -84,7 +84,7 @@ import {
|
|
|
84
84
|
siteCrawlPages,
|
|
85
85
|
siteCrawlSnapshots,
|
|
86
86
|
trafficSources
|
|
87
|
-
} from "./chunk-
|
|
87
|
+
} from "./chunk-P5VXVFQW.js";
|
|
88
88
|
import {
|
|
89
89
|
RunKinds,
|
|
90
90
|
SiteCrawlFetchStates,
|
|
@@ -108,7 +108,7 @@ import {
|
|
|
108
108
|
placementLinkDecision,
|
|
109
109
|
siteAuditPageFactorSchema,
|
|
110
110
|
wilsonInterval
|
|
111
|
-
} from "./chunk-
|
|
111
|
+
} from "./chunk-S5OSY3PI.js";
|
|
112
112
|
|
|
113
113
|
// src/demo-server.ts
|
|
114
114
|
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-XFHXKLNT.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-GLLY2GEV.js";
|
|
10
|
+
import "./chunk-3LCR6WU6.js";
|
|
11
|
+
import "./chunk-DDL2XSNM.js";
|
|
12
|
+
import "./chunk-P5VXVFQW.js";
|
|
13
|
+
import "./chunk-S5OSY3PI.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-YTSXQUJ3.js";
|
|
4
4
|
import {
|
|
5
5
|
createApiClient,
|
|
6
6
|
createCanonryMcpServer
|
|
7
|
-
} from "./chunk-
|
|
8
|
-
import "./chunk-
|
|
7
|
+
} from "./chunk-GLLY2GEV.js";
|
|
8
|
+
import "./chunk-DDL2XSNM.js";
|
|
9
9
|
import {
|
|
10
10
|
isReadOnlyKey,
|
|
11
11
|
updateCheckEnvOptOut
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-S5OSY3PI.js";
|
|
13
13
|
|
|
14
14
|
// src/mcp/cli.ts
|
|
15
15
|
import { randomUUID } from "crypto";
|