@canonry/canonry 7.16.0 → 7.17.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/canonry/references/canonry-cli.md +22 -6
- package/assets/assets/{AuditHistoryPanel-Cl9tUvSZ.js → AuditHistoryPanel-CUde9U_6.js} +1 -1
- package/assets/assets/{BacklinksPage-CTeTJ9dh.js → BacklinksPage-DMQPw8ks.js} +1 -1
- package/assets/assets/{HistoryPage-DpOoXr2P.js → HistoryPage-DZSa1gYf.js} +1 -1
- package/assets/assets/{MeasurementPropertyPage-DxXsgM25.js → MeasurementPropertyPage-DgW17Jpd.js} +1 -1
- package/assets/assets/ProjectPage-C8vdtqtA.js +8 -0
- package/assets/assets/{RunsPage-CfDi7I1z.js → RunsPage-DRfNd-Jp.js} +1 -1
- package/assets/assets/{SettingsPage-BHDb1apK.js → SettingsPage-D38Gl1Nv.js} +1 -1
- package/assets/assets/{SiteHealthSection-DQZyy4P_.js → SiteHealthSection-CR3zB84D.js} +3 -3
- package/assets/assets/{TrafficPage-DX_vN2RL.js → TrafficPage-DX3qRPgQ.js} +2 -2
- package/assets/assets/{TrafficSourceDetailPage-Cg92zrtZ.js → TrafficSourceDetailPage-CigB82vX.js} +1 -1
- package/assets/assets/{extract-error-message-BKxVCbov.js → extract-error-message-DsMnnkxT.js} +1 -1
- package/assets/assets/{index-DoQJETc6.js → index-DBr6ISbx.js} +25 -25
- package/assets/assets/{react-sigma_core.esm.min-BhqZcSgh.js → react-sigma_core.esm.min-CkYxzGpi.js} +1 -1
- package/assets/assets/{v2-overview-adapter-DZ5YsE_G.js → v2-overview-adapter-5x8UiA07.js} +1 -1
- package/assets/index.html +1 -1
- package/dist/{chunk-O6XPXEN6.js → chunk-2MBI5SYB.js} +3 -3
- package/dist/{chunk-SPZRSKCF.js → chunk-3NAZXITW.js} +1381 -797
- package/dist/{chunk-6LS2R477.js → chunk-PVWGKDY6.js} +98 -2
- package/dist/{chunk-2S7U2YHI.js → chunk-QPOXDS43.js} +2 -2
- package/dist/{chunk-KDWTNI4Z.js → chunk-RBQUGZM4.js} +23 -1
- package/dist/{chunk-VWSUFTW5.js → chunk-WEKVQK3O.js} +6 -6
- package/dist/{chunk-3ZGBSHZ2.js → chunk-WVBLFG7H.js} +30 -3
- package/dist/cli.js +123 -12
- package/dist/{demo-server-6OE3H2KL.js → demo-server-BVJFYR4V.js} +68 -15
- package/dist/index.js +6 -6
- package/dist/{intelligence-service-USSTKAKC.js → intelligence-service-FK2W72X7.js} +2 -2
- package/dist/mcp.js +4 -4
- package/package.json +14 -14
- package/assets/assets/ProjectPage-By9arjLJ.js +0 -8
|
@@ -17416,6 +17416,84 @@ var ga4PropertySummaryDtoSchema = z51.object({
|
|
|
17416
17416
|
var ga4PropertiesDtoSchema = z51.object({
|
|
17417
17417
|
properties: z51.array(ga4PropertySummaryDtoSchema)
|
|
17418
17418
|
});
|
|
17419
|
+
var gaSearchLandingWindowSchema = z51.enum(["7d", "28d", "90d"]);
|
|
17420
|
+
var GA_SEARCH_LANDING_WINDOWS = gaSearchLandingWindowSchema.options;
|
|
17421
|
+
var GA_SEARCH_LANDING_WINDOW_DAYS = {
|
|
17422
|
+
"7d": 7,
|
|
17423
|
+
"28d": 28,
|
|
17424
|
+
"90d": 90
|
|
17425
|
+
};
|
|
17426
|
+
var GA_SEARCH_LANDING_DEFAULT_WINDOW = "28d";
|
|
17427
|
+
var GA_SEARCH_LANDING_DEFAULT_LIMIT = 50;
|
|
17428
|
+
var GA_SEARCH_LANDING_MAX_LIMIT = 1e3;
|
|
17429
|
+
var gaSearchLandingStatusSchema = z51.enum(["never-synced", "ready", "unavailable", "error"]);
|
|
17430
|
+
var gaSearchLandingMetricsSchema = z51.object({
|
|
17431
|
+
organicGoogleSearchClicks: z51.number().int().nonnegative(),
|
|
17432
|
+
organicGoogleSearchImpressions: z51.number().int().nonnegative(),
|
|
17433
|
+
/** GA4's own click-through rate (0..1). Null when there were no impressions. */
|
|
17434
|
+
organicGoogleSearchClickThroughRate: fraction(z51.number().min(0).max(1)).nullable(),
|
|
17435
|
+
/** GA4's own average position. Null when there were no impressions. */
|
|
17436
|
+
organicGoogleSearchAveragePosition: z51.number().nonnegative().nullable(),
|
|
17437
|
+
/**
|
|
17438
|
+
* GA4's plain `activeUsers` from the same request, which is what GA4's own
|
|
17439
|
+
* report shows in this column (verified against the GA4 UI). Not limited to
|
|
17440
|
+
* Google organic sessions.
|
|
17441
|
+
*/
|
|
17442
|
+
activeUsers: z51.number().int().nonnegative()
|
|
17443
|
+
});
|
|
17444
|
+
var gaSearchLandingPageRowSchema = gaSearchLandingMetricsSchema.extend({
|
|
17445
|
+
/** GA4's `landingPagePlusQueryString`, exactly as reported (never normalized). */
|
|
17446
|
+
landingPage: z51.string()
|
|
17447
|
+
});
|
|
17448
|
+
var gaSearchLandingPagesResponseSchema = z51.object({
|
|
17449
|
+
source: z51.literal("ga4-search-console-link"),
|
|
17450
|
+
status: gaSearchLandingStatusSchema,
|
|
17451
|
+
/** The last failed attempt's message (Google's own text for `unavailable`). */
|
|
17452
|
+
error: z51.string().nullable(),
|
|
17453
|
+
/** When the stored snapshot was written. Null when none exists. */
|
|
17454
|
+
syncedAt: z51.string().datetime().nullable(),
|
|
17455
|
+
/** When a sync last tried to refresh the snapshot, successful or not. */
|
|
17456
|
+
attemptedAt: z51.string().datetime().nullable(),
|
|
17457
|
+
window: gaSearchLandingWindowSchema,
|
|
17458
|
+
/** Inclusive first day of the stored window, in the property's time zone. */
|
|
17459
|
+
windowStart: z51.iso.date().nullable(),
|
|
17460
|
+
/** Inclusive last day of the stored window (yesterday at sync time). */
|
|
17461
|
+
windowEnd: z51.iso.date().nullable(),
|
|
17462
|
+
windowDays: z51.number().int().positive().nullable(),
|
|
17463
|
+
/** GA4 property reporting time zone the window dates are in. */
|
|
17464
|
+
timeZone: z51.string().nullable(),
|
|
17465
|
+
subjectToThresholding: z51.boolean(),
|
|
17466
|
+
dataLossFromOtherRow: z51.boolean(),
|
|
17467
|
+
/** GA4's own TOTAL row for the window. Never a sum of `rows`. Null when no snapshot exists. */
|
|
17468
|
+
total: gaSearchLandingMetricsSchema.nullable(),
|
|
17469
|
+
/** Rows GA4 reported for the window. Can exceed `totalRows` when `rowsCapped`. */
|
|
17470
|
+
reportRowCount: z51.number().int().nonnegative().nullable(),
|
|
17471
|
+
/** True when GA4 reported more rows than were stored (the per-window row cap). */
|
|
17472
|
+
rowsCapped: z51.boolean(),
|
|
17473
|
+
/** Stored rows for the window, the population `limit` / `offset` page over. */
|
|
17474
|
+
totalRows: z51.number().int().nonnegative(),
|
|
17475
|
+
limit: z51.number().int().positive(),
|
|
17476
|
+
offset: z51.number().int().nonnegative(),
|
|
17477
|
+
/** Ordered by clicks, then impressions (both descending), then landing page. */
|
|
17478
|
+
rows: z51.array(gaSearchLandingPageRowSchema)
|
|
17479
|
+
});
|
|
17480
|
+
function gaSearchLandingHasSearchData(total) {
|
|
17481
|
+
return total.organicGoogleSearchClicks > 0 || total.organicGoogleSearchImpressions > 0;
|
|
17482
|
+
}
|
|
17483
|
+
var gaSearchLandingSyncResultSchema = z51.object({
|
|
17484
|
+
status: z51.enum(["ready", "unavailable", "error"]),
|
|
17485
|
+
/** Windows written by this sync, empty unless `ready`. */
|
|
17486
|
+
windows: z51.array(z51.object({
|
|
17487
|
+
window: gaSearchLandingWindowSchema,
|
|
17488
|
+
rowCount: z51.number().int().nonnegative(),
|
|
17489
|
+
reportRowCount: z51.number().int().nonnegative(),
|
|
17490
|
+
rowsCapped: z51.boolean()
|
|
17491
|
+
})),
|
|
17492
|
+
/** Landing-page rows written across every window. */
|
|
17493
|
+
rowCount: z51.number().int().nonnegative(),
|
|
17494
|
+
error: z51.string().optional()
|
|
17495
|
+
});
|
|
17496
|
+
var gaSyncOnlySchema = z51.enum(["traffic", "ai", "social", "search-landing"]);
|
|
17419
17497
|
var ga4SyncResponseDtoSchema = z51.object({
|
|
17420
17498
|
synced: z51.boolean(),
|
|
17421
17499
|
rowCount: z51.number().int().nonnegative(),
|
|
@@ -17438,12 +17516,21 @@ var ga4SyncResponseDtoSchema = z51.object({
|
|
|
17438
17516
|
syncedAt: z51.string(),
|
|
17439
17517
|
measurement: z51.object({
|
|
17440
17518
|
acquisition: z51.object({ days: z51.number().int().nonnegative(), status: z51.enum(["ready", "error"]), rowCount: z51.number().int().nonnegative(), error: z51.string().optional() }),
|
|
17441
|
-
leads: z51.object({ days: z51.number().int().nonnegative(), status: z51.enum(["ready", "error", "not-configured"]), rowCount: z51.number().int().nonnegative(), attributionScope: z51.enum(["landing-page", "channel"]).optional(), error: z51.string().optional() })
|
|
17519
|
+
leads: z51.object({ days: z51.number().int().nonnegative(), status: z51.enum(["ready", "error", "not-configured"]), rowCount: z51.number().int().nonnegative(), attributionScope: z51.enum(["landing-page", "channel"]).optional(), error: z51.string().optional() }),
|
|
17520
|
+
/**
|
|
17521
|
+
* GA4's Search Console landing-page snapshot. Absent when `only` names
|
|
17522
|
+
* another slice, since this sync did not attempt it. Its failure never
|
|
17523
|
+
* fails the sync: the previous snapshot is kept.
|
|
17524
|
+
*/
|
|
17525
|
+
searchLandingPages: gaSearchLandingSyncResultSchema.optional()
|
|
17442
17526
|
}),
|
|
17443
17527
|
/**
|
|
17444
17528
|
* Components that were written this run. Present when `only` is set.
|
|
17445
17529
|
* Always includes `traffic` and `summary` (the share denominator) plus
|
|
17446
|
-
* the requested
|
|
17530
|
+
* the requested slice: `ai`, `social` or `search-landing`. `search-landing`
|
|
17531
|
+
* fails soft, so it is listed only when its snapshot was stored; a failed
|
|
17532
|
+
* or `unavailable` attempt is left out and reported in
|
|
17533
|
+
* `measurement.searchLandingPages`.
|
|
17447
17534
|
*/
|
|
17448
17535
|
syncedComponents: z51.array(z51.string()).optional()
|
|
17449
17536
|
});
|
|
@@ -23063,6 +23150,15 @@ export {
|
|
|
23063
23150
|
formatAiReferralClassSummary,
|
|
23064
23151
|
ga4StatusDtoSchema,
|
|
23065
23152
|
ga4PropertiesDtoSchema,
|
|
23153
|
+
gaSearchLandingWindowSchema,
|
|
23154
|
+
GA_SEARCH_LANDING_WINDOWS,
|
|
23155
|
+
GA_SEARCH_LANDING_WINDOW_DAYS,
|
|
23156
|
+
GA_SEARCH_LANDING_DEFAULT_WINDOW,
|
|
23157
|
+
GA_SEARCH_LANDING_DEFAULT_LIMIT,
|
|
23158
|
+
GA_SEARCH_LANDING_MAX_LIMIT,
|
|
23159
|
+
gaSearchLandingPagesResponseSchema,
|
|
23160
|
+
gaSearchLandingHasSearchData,
|
|
23161
|
+
gaSyncOnlySchema,
|
|
23066
23162
|
ga4SyncResponseDtoSchema,
|
|
23067
23163
|
GaMoverChangeBases,
|
|
23068
23164
|
gaSocialReferralTrendResponseSchema,
|
|
@@ -5,7 +5,7 @@ import {
|
|
|
5
5
|
siteCrawlGraphNodes,
|
|
6
6
|
siteCrawlPages,
|
|
7
7
|
siteCrawlSnapshots
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-3NAZXITW.js";
|
|
9
9
|
import {
|
|
10
10
|
SITE_CRAWL_GRAPH_MAX_EDGES,
|
|
11
11
|
SITE_CRAWL_GRAPH_MAX_NODES,
|
|
@@ -14,7 +14,7 @@ import {
|
|
|
14
14
|
factorStatusFromDistribution,
|
|
15
15
|
factorStatusFromScore,
|
|
16
16
|
roundPreservingTotal
|
|
17
|
-
} from "./chunk-
|
|
17
|
+
} from "./chunk-PVWGKDY6.js";
|
|
18
18
|
|
|
19
19
|
// src/site-audit-factors.ts
|
|
20
20
|
function recordedSharePct(factor) {
|
|
@@ -3,6 +3,7 @@ import {
|
|
|
3
3
|
AGENT_MEMORY_VALUE_MAX_BYTES,
|
|
4
4
|
DISCOVERY_MAX_PROBES_CAP,
|
|
5
5
|
DISCOVERY_PROBE_CONCURRENCY_CAP,
|
|
6
|
+
GA_SEARCH_LANDING_MAX_LIMIT,
|
|
6
7
|
GOOGLE_MARKETING_STORED_SNAPSHOT_PAGE_MAX,
|
|
7
8
|
LATEST_RUN_ID,
|
|
8
9
|
PROVIDER_ACCOUNT_FAILURE_STREAK,
|
|
@@ -44,6 +45,7 @@ import {
|
|
|
44
45
|
feedbackSubmissionSchema,
|
|
45
46
|
gaMeasurementAnalysisWindowSchema,
|
|
46
47
|
gaMeasurementHostScopeSchema,
|
|
48
|
+
gaSearchLandingWindowSchema,
|
|
47
49
|
googleAdsMetricsWindowSchema,
|
|
48
50
|
gscPerformanceOrderBySchema,
|
|
49
51
|
keywordBatchRequestSchema,
|
|
@@ -139,7 +141,7 @@ import {
|
|
|
139
141
|
trafficSeriesGranularitySchema,
|
|
140
142
|
visibilityCompareSelectionSchema,
|
|
141
143
|
visibilityReportRequestSchema
|
|
142
|
-
} from "./chunk-
|
|
144
|
+
} from "./chunk-PVWGKDY6.js";
|
|
143
145
|
|
|
144
146
|
// src/cli-error.ts
|
|
145
147
|
function isMachineFormat(format) {
|
|
@@ -719,6 +721,12 @@ var gaMeasurementAnalysisInputSchema = z3.object({
|
|
|
719
721
|
pathPrefix: z3.string().min(1).optional(),
|
|
720
722
|
limit: z3.number().int().positive().max(100).optional()
|
|
721
723
|
});
|
|
724
|
+
var gaSearchLandingPagesInputSchema = z3.object({
|
|
725
|
+
project: projectNameSchema,
|
|
726
|
+
window: gaSearchLandingWindowSchema.optional(),
|
|
727
|
+
limit: z3.number().int().positive().max(GA_SEARCH_LANDING_MAX_LIMIT).optional(),
|
|
728
|
+
offset: z3.number().int().nonnegative().optional()
|
|
729
|
+
});
|
|
722
730
|
var queriesInputSchema = z3.object({
|
|
723
731
|
project: projectNameSchema,
|
|
724
732
|
request: queryBatchRequestSchema
|
|
@@ -2291,6 +2299,20 @@ var canonryMcpTools = [
|
|
|
2291
2299
|
compactStringParams(input, ["window", "hostScope", "pathPrefix", "limit"])
|
|
2292
2300
|
)
|
|
2293
2301
|
}),
|
|
2302
|
+
defineTool({
|
|
2303
|
+
name: "canonry_ga_search_landing_pages",
|
|
2304
|
+
title: "Get GA4 Google organic search landing pages",
|
|
2305
|
+
description: "Read GA4's \"Google organic search traffic: Landing page + query string\" report (Search Console link) as the last GA sync stored it: clicks, impressions, CTR, average position and active users per landing page for the 7, 28 (default) or 90 days ending yesterday in the property time zone. `total` is GA4's own Total row; never sum `rows`. Status `unavailable` means GA4 refused the Search Console metrics (link Search Console in GA4); the previous snapshot is still returned. Stored data only.",
|
|
2306
|
+
access: "read",
|
|
2307
|
+
tier: "ga",
|
|
2308
|
+
inputSchema: gaSearchLandingPagesInputSchema,
|
|
2309
|
+
annotations: readAnnotations(),
|
|
2310
|
+
openApiOperations: ["GET /api/v1/projects/{name}/ga/search-landing-pages"],
|
|
2311
|
+
handler: (client, input) => client.gaSearchLandingPages(
|
|
2312
|
+
input.project,
|
|
2313
|
+
compactStringParams(input, ["window", "limit", "offset"])
|
|
2314
|
+
)
|
|
2315
|
+
}),
|
|
2294
2316
|
defineTool({
|
|
2295
2317
|
name: "canonry_ga_traffic",
|
|
2296
2318
|
title: "Get GA traffic",
|
|
@@ -20,20 +20,20 @@ import {
|
|
|
20
20
|
saveConfig,
|
|
21
21
|
saveConfigPatch,
|
|
22
22
|
sentimentInstallReadiness
|
|
23
|
-
} from "./chunk-
|
|
23
|
+
} from "./chunk-WVBLFG7H.js";
|
|
24
24
|
import {
|
|
25
25
|
computeFactorAverages,
|
|
26
26
|
deleteSiteCrawlGraphLayout,
|
|
27
27
|
persistSiteCrawlGraphLayout,
|
|
28
28
|
prepareSiteCrawlGraphLayout,
|
|
29
29
|
recordedSharePct
|
|
30
|
-
} from "./chunk-
|
|
30
|
+
} from "./chunk-QPOXDS43.js";
|
|
31
31
|
import {
|
|
32
32
|
CanonryMcpToolNames,
|
|
33
33
|
CliError,
|
|
34
34
|
PACKAGE_VERSION,
|
|
35
35
|
canonryMcpTools
|
|
36
|
-
} from "./chunk-
|
|
36
|
+
} from "./chunk-RBQUGZM4.js";
|
|
37
37
|
import {
|
|
38
38
|
CC_CACHE_DIR,
|
|
39
39
|
DUCKDB_SPEC,
|
|
@@ -217,7 +217,7 @@ import {
|
|
|
217
217
|
siteLivenessState,
|
|
218
218
|
toAlertView,
|
|
219
219
|
usageCounters
|
|
220
|
-
} from "./chunk-
|
|
220
|
+
} from "./chunk-3NAZXITW.js";
|
|
221
221
|
import {
|
|
222
222
|
AGENT_MEMORY_VALUE_MAX_BYTES,
|
|
223
223
|
AGENT_NONE,
|
|
@@ -432,7 +432,7 @@ import {
|
|
|
432
432
|
winnabilityClassLabel,
|
|
433
433
|
withRetry,
|
|
434
434
|
withSkippedProviders
|
|
435
|
-
} from "./chunk-
|
|
435
|
+
} from "./chunk-PVWGKDY6.js";
|
|
436
436
|
|
|
437
437
|
// src/runtime-context.ts
|
|
438
438
|
function cliRuntimeContext(env = process.env, stdio = process) {
|
|
@@ -8045,7 +8045,7 @@ function nonBlank(value) {
|
|
|
8045
8045
|
return trimmed ? trimmed : void 0;
|
|
8046
8046
|
}
|
|
8047
8047
|
function resolveBuildCommit(env = process.env) {
|
|
8048
|
-
const embedded = true ? "
|
|
8048
|
+
const embedded = true ? "292663bc656bcd51a4a32fa879fbdcd7f7935398" : void 0;
|
|
8049
8049
|
return nonBlank(embedded) ?? nonBlank(env.CANONRY_COMMIT);
|
|
8050
8050
|
}
|
|
8051
8051
|
function resolveInstanceIdentity(env = process.env) {
|
|
@@ -5,7 +5,7 @@ import {
|
|
|
5
5
|
PACKAGE_VERSION,
|
|
6
6
|
canonryMcpTools,
|
|
7
7
|
isMachineFormat
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-RBQUGZM4.js";
|
|
9
9
|
import {
|
|
10
10
|
AGENT_PROVIDER_IDS,
|
|
11
11
|
CANONRY_NPM_PACKAGE_URL,
|
|
@@ -50,7 +50,7 @@ import {
|
|
|
50
50
|
skillsClientSchema,
|
|
51
51
|
upgradeCaveatFor,
|
|
52
52
|
upgradeCommandFor
|
|
53
|
-
} from "./chunk-
|
|
53
|
+
} from "./chunk-PVWGKDY6.js";
|
|
54
54
|
|
|
55
55
|
// src/config.ts
|
|
56
56
|
import fs from "fs";
|
|
@@ -5212,6 +5212,18 @@ var getApiV1ProjectsByNameGaMeasurementAnalysis = (options) => {
|
|
|
5212
5212
|
...options
|
|
5213
5213
|
});
|
|
5214
5214
|
};
|
|
5215
|
+
var getApiV1ProjectsByNameGaSearchLandingPages = (options) => {
|
|
5216
|
+
return (options.client ?? client).get({
|
|
5217
|
+
security: [
|
|
5218
|
+
{
|
|
5219
|
+
scheme: "bearer",
|
|
5220
|
+
type: "http"
|
|
5221
|
+
}
|
|
5222
|
+
],
|
|
5223
|
+
url: "/api/v1/projects/{name}/ga/search-landing-pages",
|
|
5224
|
+
...options
|
|
5225
|
+
});
|
|
5226
|
+
};
|
|
5215
5227
|
var postApiV1ProjectsByNameGaSync = (options) => {
|
|
5216
5228
|
return (options.client ?? client).post({
|
|
5217
5229
|
security: [
|
|
@@ -8598,11 +8610,26 @@ var ApiClient = class {
|
|
|
8598
8610
|
})
|
|
8599
8611
|
);
|
|
8600
8612
|
}
|
|
8613
|
+
/**
|
|
8614
|
+
* One stored window of GA4's Search Console landing-page report
|
|
8615
|
+
* (`window`, `limit`, `offset`). Its `total` is GA4's own Total row.
|
|
8616
|
+
*/
|
|
8617
|
+
async gaSearchLandingPages(project, params) {
|
|
8618
|
+
return this.invoke(
|
|
8619
|
+
() => getApiV1ProjectsByNameGaSearchLandingPages({
|
|
8620
|
+
client: this.heyClient,
|
|
8621
|
+
path: { name: project },
|
|
8622
|
+
query: params
|
|
8623
|
+
})
|
|
8624
|
+
);
|
|
8625
|
+
}
|
|
8601
8626
|
async gaSync(project, body) {
|
|
8602
8627
|
return this.invoke(
|
|
8603
8628
|
() => postApiV1ProjectsByNameGaSync({
|
|
8604
8629
|
client: this.heyClient,
|
|
8605
8630
|
path: { name: project },
|
|
8631
|
+
// `--only` is forwarded verbatim: the server validates it against
|
|
8632
|
+
// `gaSyncOnlySchema` and names the accepted values in its 400.
|
|
8606
8633
|
body: body ?? {}
|
|
8607
8634
|
})
|
|
8608
8635
|
);
|
|
@@ -9694,7 +9721,7 @@ var CANONRY_MCP_TOOLKITS = [
|
|
|
9694
9721
|
{
|
|
9695
9722
|
name: "ga",
|
|
9696
9723
|
title: "Google Analytics 4",
|
|
9697
|
-
description: "Read GA traffic, AI/social referral history, attribution trend, and
|
|
9724
|
+
description: "Read GA traffic, AI/social referral history, attribution trend, session history, and GA4's Search Console landing-page report (Google organic clicks, impressions, CTR, position and active users per landing page).",
|
|
9698
9725
|
whenToLoad: "Load when you need traffic, referral, or attribution data from Google Analytics 4."
|
|
9699
9726
|
},
|
|
9700
9727
|
{
|
package/dist/cli.js
CHANGED
|
@@ -33,11 +33,11 @@ import {
|
|
|
33
33
|
trackCliCommandFinished,
|
|
34
34
|
trackEvent,
|
|
35
35
|
waitForServerRuntimeStartup
|
|
36
|
-
} from "./chunk-
|
|
36
|
+
} from "./chunk-WEKVQK3O.js";
|
|
37
37
|
import {
|
|
38
38
|
autoSyncSkills,
|
|
39
39
|
formatAutoSyncNotice
|
|
40
|
-
} from "./chunk-
|
|
40
|
+
} from "./chunk-2MBI5SYB.js";
|
|
41
41
|
import {
|
|
42
42
|
configExists,
|
|
43
43
|
createApiClient,
|
|
@@ -54,13 +54,13 @@ import {
|
|
|
54
54
|
saveConfig,
|
|
55
55
|
saveConfigPatch,
|
|
56
56
|
shouldPrintServeSkillsNudge
|
|
57
|
-
} from "./chunk-
|
|
57
|
+
} from "./chunk-WVBLFG7H.js";
|
|
58
58
|
import {
|
|
59
59
|
DEFAULT_DEMO_TRUSTED_PROXIES,
|
|
60
60
|
trustedProxiesProblem,
|
|
61
61
|
trustedProxyProblem
|
|
62
62
|
} from "./chunk-RB2F4D3Z.js";
|
|
63
|
-
import "./chunk-
|
|
63
|
+
import "./chunk-QPOXDS43.js";
|
|
64
64
|
import {
|
|
65
65
|
CliError,
|
|
66
66
|
EXIT_SYSTEM_ERROR,
|
|
@@ -72,7 +72,7 @@ import {
|
|
|
72
72
|
runMeasurementDraftAction,
|
|
73
73
|
systemError,
|
|
74
74
|
usageError
|
|
75
|
-
} from "./chunk-
|
|
75
|
+
} from "./chunk-RBQUGZM4.js";
|
|
76
76
|
import {
|
|
77
77
|
CLOUDFLARE_WORKER_BINDINGS,
|
|
78
78
|
CLOUDFLARE_WORKER_GENERATED_MARKER,
|
|
@@ -104,7 +104,7 @@ import {
|
|
|
104
104
|
rawEventSamples,
|
|
105
105
|
readMarketCompetitorNames,
|
|
106
106
|
runs
|
|
107
|
-
} from "./chunk-
|
|
107
|
+
} from "./chunk-3NAZXITW.js";
|
|
108
108
|
import {
|
|
109
109
|
AdsDeliverySnapshotStatuses,
|
|
110
110
|
AdsHistoricalCampaignRollupStatuses,
|
|
@@ -119,6 +119,7 @@ import {
|
|
|
119
119
|
CitationStates,
|
|
120
120
|
DiscoveryPromoteCompetitorSkipReasons,
|
|
121
121
|
FEEDBACK_KINDS,
|
|
122
|
+
GA_SEARCH_LANDING_WINDOW_DAYS,
|
|
122
123
|
GaMoverChangeBases,
|
|
123
124
|
MeasurementEvidenceShapes,
|
|
124
125
|
OUTSTANDING_PROVIDER_BATCH_STATUSES,
|
|
@@ -181,6 +182,7 @@ import {
|
|
|
181
182
|
formatRunErrorOneLine,
|
|
182
183
|
formatSignedPointDelta,
|
|
183
184
|
formatSiteAuditPageBudget,
|
|
185
|
+
gaSearchLandingHasSearchData,
|
|
184
186
|
gbpNegativeReviewMaxStarsSchema,
|
|
185
187
|
googleAdsMetricsWindowSchema,
|
|
186
188
|
isRetiredAgentProviderId,
|
|
@@ -234,7 +236,7 @@ import {
|
|
|
234
236
|
visibilityCompareSelectionSchema,
|
|
235
237
|
visibilityReportRequestSchema,
|
|
236
238
|
winnabilityClassSchema
|
|
237
|
-
} from "./chunk-
|
|
239
|
+
} from "./chunk-PVWGKDY6.js";
|
|
238
240
|
|
|
239
241
|
// src/cli.ts
|
|
240
242
|
import { pathToFileURL } from "url";
|
|
@@ -784,7 +786,7 @@ function parseDemoTrustedProxies(values) {
|
|
|
784
786
|
async function demoCommand(options) {
|
|
785
787
|
const { host, port } = parseDemoListenOptions(options);
|
|
786
788
|
const trustProxy = parseDemoTrustedProxies(options.trustProxy);
|
|
787
|
-
const { createDemoServer } = await import("./demo-server-
|
|
789
|
+
const { createDemoServer } = await import("./demo-server-BVJFYR4V.js");
|
|
788
790
|
const app = await createDemoServer({ trustProxy });
|
|
789
791
|
let stopping = false;
|
|
790
792
|
const stop = () => {
|
|
@@ -1198,7 +1200,7 @@ No DB writes performed. Re-run without --dry-run to apply.`);
|
|
|
1198
1200
|
}
|
|
1199
1201
|
}
|
|
1200
1202
|
async function backfillInsightsCommand(project2, opts) {
|
|
1201
|
-
const { IntelligenceService } = await import("./intelligence-service-
|
|
1203
|
+
const { IntelligenceService } = await import("./intelligence-service-FK2W72X7.js");
|
|
1202
1204
|
const config = loadConfig();
|
|
1203
1205
|
const db = createClient(config.database);
|
|
1204
1206
|
migrate(db);
|
|
@@ -5437,8 +5439,99 @@ async function gaSync(project2, opts) {
|
|
|
5437
5439
|
console.log(` AI rows: ${result.aiReferralCount}`);
|
|
5438
5440
|
console.log(` Social rows: ${result.socialReferralCount}`);
|
|
5439
5441
|
console.log(` Period: ${result.days} days${result.clamped ? ` (requested ${result.requestedDays})` : ""}`);
|
|
5442
|
+
const searchLanding = result.measurement.searchLandingPages;
|
|
5443
|
+
if (searchLanding) {
|
|
5444
|
+
console.log(` Search Console landing pages: ${searchLanding.status} (${searchLanding.rowCount} rows)`);
|
|
5445
|
+
if (searchLanding.error) console.log(` Error: ${searchLanding.error}`);
|
|
5446
|
+
}
|
|
5440
5447
|
console.log(` Synced at: ${result.syncedAt}`);
|
|
5441
5448
|
}
|
|
5449
|
+
var SEARCH_LANDING_NOT_AVAILABLE = "n/a";
|
|
5450
|
+
function searchLandingCells(metrics) {
|
|
5451
|
+
return [
|
|
5452
|
+
metrics.organicGoogleSearchClicks.toLocaleString("en-US"),
|
|
5453
|
+
metrics.organicGoogleSearchImpressions.toLocaleString("en-US"),
|
|
5454
|
+
metrics.organicGoogleSearchClickThroughRate === null ? SEARCH_LANDING_NOT_AVAILABLE : formatPercent(metrics.organicGoogleSearchClickThroughRate),
|
|
5455
|
+
metrics.organicGoogleSearchAveragePosition === null ? SEARCH_LANDING_NOT_AVAILABLE : metrics.organicGoogleSearchAveragePosition.toFixed(1),
|
|
5456
|
+
metrics.activeUsers.toLocaleString("en-US")
|
|
5457
|
+
];
|
|
5458
|
+
}
|
|
5459
|
+
async function gaSearchLandingPages(project2, opts) {
|
|
5460
|
+
const client = getClient7();
|
|
5461
|
+
const params = {};
|
|
5462
|
+
if (opts?.window) params.window = opts.window;
|
|
5463
|
+
if (opts?.limit) params.limit = opts.limit;
|
|
5464
|
+
if (opts?.offset) params.offset = opts.offset;
|
|
5465
|
+
const result = await client.gaSearchLandingPages(
|
|
5466
|
+
project2,
|
|
5467
|
+
Object.keys(params).length > 0 ? params : void 0
|
|
5468
|
+
);
|
|
5469
|
+
if (opts?.format === "json") {
|
|
5470
|
+
console.log(JSON.stringify(result, null, 2));
|
|
5471
|
+
return;
|
|
5472
|
+
} else if (opts?.format === "jsonl") {
|
|
5473
|
+
emitJsonl(result.rows.map((row) => ({
|
|
5474
|
+
project: project2,
|
|
5475
|
+
window: result.window,
|
|
5476
|
+
windowStart: result.windowStart,
|
|
5477
|
+
windowEnd: result.windowEnd,
|
|
5478
|
+
...row
|
|
5479
|
+
})));
|
|
5480
|
+
return;
|
|
5481
|
+
}
|
|
5482
|
+
if (result.status === "never-synced") {
|
|
5483
|
+
console.log(`No GA4 Search Console landing-page data for "${project2}" yet. Run "canonry ga sync ${project2}".`);
|
|
5484
|
+
return;
|
|
5485
|
+
}
|
|
5486
|
+
console.log(`Google organic search traffic: landing page + query string (GA4 Search Console link) for "${project2}"`);
|
|
5487
|
+
if (result.windowStart && result.windowEnd) {
|
|
5488
|
+
console.log(`Last ${result.windowDays ?? GA_SEARCH_LANDING_WINDOW_DAYS[result.window]} days: ${result.windowStart} to ${result.windowEnd}${result.timeZone ? ` (${result.timeZone})` : ""}`);
|
|
5489
|
+
}
|
|
5490
|
+
if (result.status === "unavailable") {
|
|
5491
|
+
console.log(`Status: unavailable. GA4 did not return Search Console data: ${result.error ?? "no reason given"}`);
|
|
5492
|
+
console.log(`Link Search Console to this GA4 property (GA4 Admin, Product links, Search Console links), then run "canonry ga sync ${project2}".`);
|
|
5493
|
+
} else if (result.status === "error") {
|
|
5494
|
+
console.log(`Status: the last refresh failed${result.attemptedAt ? ` (${result.attemptedAt})` : ""}: ${result.error ?? "unknown error"}`);
|
|
5495
|
+
}
|
|
5496
|
+
if (result.status !== "ready" && result.total) {
|
|
5497
|
+
console.log(`Showing the snapshot synced ${result.syncedAt ?? "earlier"}.`);
|
|
5498
|
+
}
|
|
5499
|
+
if (!result.total) {
|
|
5500
|
+
console.log("No stored snapshot.");
|
|
5501
|
+
return;
|
|
5502
|
+
}
|
|
5503
|
+
const headers = ["LANDING PAGE", "CLICKS", "IMPRESSIONS", "CTR", "AVG POSITION", "ACTIVE USERS"];
|
|
5504
|
+
const table = [
|
|
5505
|
+
["Total", ...searchLandingCells(result.total)],
|
|
5506
|
+
...result.rows.map((row) => [row.landingPage, ...searchLandingCells(row)])
|
|
5507
|
+
];
|
|
5508
|
+
const pageWidth = Math.min(60, Math.max(headers[0].length, ...table.map((row) => row[0].length)));
|
|
5509
|
+
const widths = headers.map((header, index) => index === 0 ? pageWidth : Math.max(header.length, ...table.map((row) => row[index].length)));
|
|
5510
|
+
const line = (cells) => ` ${cells.map((cell2, index) => index === 0 ? (cell2.length > pageWidth ? `${cell2.slice(0, pageWidth - 3)}...` : cell2).padEnd(pageWidth) : cell2.padStart(widths[index])).join(" ")}`;
|
|
5511
|
+
console.log();
|
|
5512
|
+
console.log(line(headers));
|
|
5513
|
+
console.log(` ${widths.map((width) => "\u2500".repeat(width)).join(" ")}`);
|
|
5514
|
+
for (const row of table) console.log(line(row));
|
|
5515
|
+
console.log();
|
|
5516
|
+
if (result.rows.length > 0) {
|
|
5517
|
+
console.log(` Showing ${result.offset + 1}-${result.offset + result.rows.length} of ${result.totalRows} pages.`);
|
|
5518
|
+
} else if (result.totalRows > 0) {
|
|
5519
|
+
console.log(` No landing-page rows at offset ${result.offset} (${result.totalRows} stored).`);
|
|
5520
|
+
}
|
|
5521
|
+
if (!gaSearchLandingHasSearchData(result.total)) {
|
|
5522
|
+
console.log(" No landing pages had Google organic search traffic in this window.");
|
|
5523
|
+
console.log(" If the property should have some, check its Search Console link in GA4 (Admin, Product links, Search Console links).");
|
|
5524
|
+
}
|
|
5525
|
+
if (result.rowsCapped && result.reportRowCount !== null) {
|
|
5526
|
+
console.log(` GA4 reported ${result.reportRowCount} rows; the ${result.totalRows} with the most clicks are stored.`);
|
|
5527
|
+
}
|
|
5528
|
+
if (result.subjectToThresholding) {
|
|
5529
|
+
console.log(" GA4 applied thresholding to this report, so some rows may be withheld.");
|
|
5530
|
+
}
|
|
5531
|
+
if (result.status === "ready" && result.syncedAt) {
|
|
5532
|
+
console.log(` Synced at: ${result.syncedAt}`);
|
|
5533
|
+
}
|
|
5534
|
+
}
|
|
5442
5535
|
async function gaTraffic(project2, opts) {
|
|
5443
5536
|
const client = getClient7();
|
|
5444
5537
|
const params = rangeParams(opts, opts?.limit ? { limit: String(opts.limit) } : void 0);
|
|
@@ -6094,13 +6187,13 @@ var GA_CLI_COMMANDS = [
|
|
|
6094
6187
|
},
|
|
6095
6188
|
{
|
|
6096
6189
|
path: ["ga", "sync"],
|
|
6097
|
-
usage: "canonry ga sync <project> [--days 30] [--only traffic|ai|social] [--format json]",
|
|
6190
|
+
usage: "canonry ga sync <project> [--days 30] [--only traffic|ai|social|search-landing] [--format json]",
|
|
6098
6191
|
options: {
|
|
6099
6192
|
days: stringOption(),
|
|
6100
6193
|
only: stringOption()
|
|
6101
6194
|
},
|
|
6102
6195
|
run: async (input) => {
|
|
6103
|
-
const project2 = requireProject(input, "ga.sync", "canonry ga sync <project> [--days 30] [--only traffic|ai|social] [--format json]");
|
|
6196
|
+
const project2 = requireProject(input, "ga.sync", "canonry ga sync <project> [--days 30] [--only traffic|ai|social|search-landing] [--format json]");
|
|
6104
6197
|
const daysStr = getString(input.values, "days");
|
|
6105
6198
|
const days = daysStr ? parseInt(daysStr, 10) : void 0;
|
|
6106
6199
|
const only = getString(input.values, "only");
|
|
@@ -6132,6 +6225,24 @@ var GA_CLI_COMMANDS = [
|
|
|
6132
6225
|
});
|
|
6133
6226
|
}
|
|
6134
6227
|
},
|
|
6228
|
+
{
|
|
6229
|
+
path: ["ga", "search-landing-pages"],
|
|
6230
|
+
usage: "canonry ga search-landing-pages <project> [--window 7d|28d|90d] [--limit 50] [--offset 0] [--format json|jsonl]",
|
|
6231
|
+
options: {
|
|
6232
|
+
window: stringOption(),
|
|
6233
|
+
limit: stringOption(),
|
|
6234
|
+
offset: stringOption()
|
|
6235
|
+
},
|
|
6236
|
+
run: async (input) => {
|
|
6237
|
+
const project2 = requireProject(input, "ga.search-landing-pages", "canonry ga search-landing-pages <project> [--window 7d|28d|90d] [--limit 50] [--offset 0] [--format json|jsonl]");
|
|
6238
|
+
await gaSearchLandingPages(project2, {
|
|
6239
|
+
window: getString(input.values, "window"),
|
|
6240
|
+
limit: getString(input.values, "limit"),
|
|
6241
|
+
offset: getString(input.values, "offset"),
|
|
6242
|
+
format: input.format
|
|
6243
|
+
});
|
|
6244
|
+
}
|
|
6245
|
+
},
|
|
6135
6246
|
{
|
|
6136
6247
|
path: ["ga", "traffic"],
|
|
6137
6248
|
usage: `canonry ga traffic <project> [--limit 50] ${RANGE_USAGE} [--format json]`,
|
|
@@ -6241,7 +6352,7 @@ var GA_CLI_COMMANDS = [
|
|
|
6241
6352
|
unknownSubcommand(input.positionals[0], {
|
|
6242
6353
|
command: "ga",
|
|
6243
6354
|
usage: "canonry ga <subcommand> <project> [args]",
|
|
6244
|
-
available: ["connect", "disconnect", "status", "properties", "sync", "measurement-analysis", "traffic", "coverage", "ai-referral-history", "ai-referral-daily", "social-referral-history", "session-history", "social-referral-summary", "attribution"]
|
|
6355
|
+
available: ["connect", "disconnect", "status", "properties", "sync", "measurement-analysis", "search-landing-pages", "traffic", "coverage", "ai-referral-history", "ai-referral-daily", "social-referral-history", "session-history", "social-referral-summary", "attribution"]
|
|
6245
6356
|
});
|
|
6246
6357
|
}
|
|
6247
6358
|
}
|