@canonry/canonry 7.67.0 → 7.68.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.
Files changed (138) hide show
  1. package/README.md +2 -0
  2. package/assets/agent-workspace/skills/aero/references/seo-analysis.md +10 -2
  3. package/assets/agent-workspace/skills/canonry/references/canonry-cli.md +5 -1
  4. package/assets/assets/{AgentSetupPage-ORsy3QEa.js → AgentSetupPage-DyssdZ1J.js} +3 -3
  5. package/assets/assets/{AuditHistoryPanel-vTHZDbfs.js → AuditHistoryPanel-Bma4Q6p0.js} +1 -1
  6. package/assets/assets/{BacklinksPage-FqADB5sO.js → BacklinksPage-C3GoO2Wf.js} +1 -1
  7. package/assets/assets/{HistoryPage-C4l5Toqa.js → HistoryPage-6iYvYCL7.js} +1 -1
  8. package/assets/assets/MeasurementPropertyPage-CjI5eB3b.js +4 -0
  9. package/assets/assets/ProjectPage-GYIgNPxn.js +9 -0
  10. package/assets/assets/{RunsPage-oyhhwAPq.js → RunsPage-Cw0GTxgx.js} +1 -1
  11. package/assets/assets/{SettingsPage-DJc4Di1M.js → SettingsPage-Cvg8BvZn.js} +1 -1
  12. package/assets/assets/SiteHealthSection-vejp2Igj.js +2 -0
  13. package/assets/assets/ToneBadge-c2bgjqqz.js +60 -0
  14. package/assets/assets/{TrafficPage-DAD0FFkL.js → TrafficPage-BUb0xr-b.js} +1 -1
  15. package/assets/assets/{TrafficSourceDetailPage-BBEzbawh.js → TrafficSourceDetailPage-DmrtEYs8.js} +1 -1
  16. package/assets/assets/{account-context-DMHOefRt.js → account-context-qhg8esXw.js} +1 -1
  17. package/assets/assets/{card-Brp6fFNG.js → card-BNthgfAY.js} +1 -1
  18. package/assets/assets/{extract-error-message-5QpQCsGb.js → extract-error-message-DuYEL09s.js} +1 -1
  19. package/assets/assets/{format-helpers-BFM0FRjT.js → format-helpers-6v-a8B3S.js} +1 -1
  20. package/assets/assets/index-BUigRGam.js +60 -0
  21. package/assets/assets/{index-C6U4u18w.css → index-CqNwsqjm.css} +1 -1
  22. package/assets/assets/{query-client-BMTW-xss.js → query-client-COFiuVJB.js} +1 -1
  23. package/assets/assets/react-query-ZdpN7cFt.js +1 -0
  24. package/assets/assets/{react-sigma_core.esm.min-C0VjhgDo.js → react-sigma_core.esm.min-EbeNATny.js} +1 -1
  25. package/assets/assets/{service-DW9u_0aZ.js → service-DGFjEsYR.js} +1 -1
  26. package/assets/index.html +8 -8
  27. package/dist/{ads-BXGEL4WI.js → ads-AHM5LMVT.js} +3 -3
  28. package/dist/{agent-LFX7GHWD.js → agent-2FSGY7SD.js} +7 -7
  29. package/dist/{agent-ask-QJV225AT.js → agent-ask-GIK7T2HD.js} +3 -3
  30. package/dist/{agent-conversations-2TZDIGA6.js → agent-conversations-JEIFZHT3.js} +3 -3
  31. package/dist/{agent-memory-XCY3ZG5C.js → agent-memory-JC3JJXON.js} +3 -3
  32. package/dist/{agent-providers-VS6PH55Y.js → agent-providers-JRL3VZA7.js} +3 -3
  33. package/dist/{agent-transcript-BUUHOTZM.js → agent-transcript-ZQDNW3IE.js} +3 -3
  34. package/dist/{analytics-YWJWPUNF.js → analytics-HMYE6EIX.js} +3 -3
  35. package/dist/{apply-BMCYFBEJ.js → apply-F5CHVFC3.js} +3 -3
  36. package/dist/{backfill-YBOKT5LT.js → backfill-JZDQKZHY.js} +9 -9
  37. package/dist/{backlinks-QNNABB4N.js → backlinks-L7XEHBAP.js} +3 -3
  38. package/dist/{bing-KEMXBABP.js → bing-XTMKLVRJ.js} +3 -3
  39. package/dist/{bootstrap-X2AADK4M.js → bootstrap-AEHBYC77.js} +10 -10
  40. package/dist/{cdp-WVYUEV4U.js → cdp-SSIHU3PU.js} +7 -7
  41. package/dist/{chunk-MLOGEXIO.js → chunk-2D7O5UHJ.js} +1 -1
  42. package/dist/{chunk-MD5PHJBX.js → chunk-33LH4ZGF.js} +2 -1
  43. package/dist/{chunk-VR4MYSEH.js → chunk-4KMUJOYL.js} +4 -4
  44. package/dist/{chunk-WSYLDPYF.js → chunk-5SK27UE7.js} +1 -1
  45. package/dist/{chunk-AVISYPUU.js → chunk-6W3ENB2X.js} +61 -7
  46. package/dist/{chunk-ZGUR4AZM.js → chunk-7AXVACK6.js} +2 -2
  47. package/dist/{chunk-WZ4LUM26.js → chunk-7NMCRHQL.js} +3 -3
  48. package/dist/{chunk-UXTNDZKM.js → chunk-7SGZHGZ2.js} +1 -1
  49. package/dist/{chunk-6DJN7HCK.js → chunk-ARIYTYOM.js} +1 -1
  50. package/dist/{chunk-XMIKSCAO.js → chunk-ARYBII44.js} +1 -1
  51. package/dist/{chunk-CBYKQRDH.js → chunk-CZUPNWLH.js} +2 -2
  52. package/dist/{chunk-AFRCTLUL.js → chunk-F4KTLNW3.js} +404 -340
  53. package/dist/{chunk-XEPEMON2.js → chunk-FDRZQH3Y.js} +14 -2
  54. package/dist/{chunk-5DMESZDF.js → chunk-IVBJEVHS.js} +2 -2
  55. package/dist/{chunk-HX3WLTZU.js → chunk-J4CNNYRQ.js} +1 -1
  56. package/dist/{chunk-Y54PMWBH.js → chunk-JPVG5LIE.js} +3 -3
  57. package/dist/{chunk-EKSXR7RJ.js → chunk-K2P2XO6P.js} +1 -1
  58. package/dist/{chunk-IEBMODUI.js → chunk-KGJ7NDUY.js} +20 -20
  59. package/dist/{chunk-KJLICF53.js → chunk-LO2EII7V.js} +4 -4
  60. package/dist/{chunk-YP743QX5.js → chunk-LTMQ4MHF.js} +1 -1
  61. package/dist/{chunk-UNCOK6DA.js → chunk-MVRPFLEL.js} +1 -1
  62. package/dist/{chunk-LU3M54IY.js → chunk-PAVSKSKA.js} +1 -1
  63. package/dist/{chunk-G6PZEDTH.js → chunk-R42VEDCB.js} +3 -3
  64. package/dist/{chunk-P74TPIWZ.js → chunk-RNA6ZCM6.js} +2 -2
  65. package/dist/{chunk-32BTTG5N.js → chunk-U3EJ5RW7.js} +12 -6
  66. package/dist/{chunk-GTPGYFZ4.js → chunk-V6ALEP33.js} +2 -2
  67. package/dist/{chunk-XEGYSZEV.js → chunk-VPZMSV3Q.js} +235 -6
  68. package/dist/{chunk-XIA6NWIF.js → chunk-W7PA35VJ.js} +4 -4
  69. package/dist/{chunk-NHHZQWMI.js → chunk-XMXYUP7X.js} +1 -1
  70. package/dist/{chunk-2X7DFLMD.js → chunk-Y42G2YKT.js} +8 -8
  71. package/dist/{chunk-37R6GTU7.js → chunk-YIIIYNPW.js} +22 -4
  72. package/dist/{chunk-MOJ2XZXK.js → chunk-ZD5G5QEV.js} +1 -1
  73. package/dist/{chunk-UHLWNU6I.js → chunk-ZU6X4SN2.js} +5 -5
  74. package/dist/{chunk-RRS7U6HQ.js → chunk-ZUXFHO4T.js} +4 -4
  75. package/dist/{citations-ZSI5BOGD.js → citations-NIFKIG6Y.js} +3 -3
  76. package/dist/{cli-catalog-J2HUCGJL.js → cli-catalog-ONYERYPV.js} +3 -3
  77. package/dist/{cli-commands-XFMVFREG.js → cli-commands-3RTJR7FD.js} +7 -7
  78. package/dist/cli.js +13 -13
  79. package/dist/{competitor-WJDN3DLP.js → competitor-NSUSTLNW.js} +3 -3
  80. package/dist/{content-K52YV4BK.js → content-W5VYYMAW.js} +3 -3
  81. package/dist/{dashboard-L6RKTP35.js → dashboard-NNA3P645.js} +6 -6
  82. package/dist/{demo-Y7XRD4X4.js → demo-5M4YGVV4.js} +1 -1
  83. package/dist/{demo-server-QNQX5CNP.js → demo-server-FDR4RKLM.js} +12 -11
  84. package/dist/{discover-UO5M7HQZ.js → discover-VCKMXFOR.js} +3 -3
  85. package/dist/{discover-eval-DN4PS6VN.js → discover-eval-CPVP7EK5.js} +3 -3
  86. package/dist/{doctor-7UYUXG7J.js → doctor-EVCP6PDM.js} +3 -3
  87. package/dist/{evidence-DGKN5SGQ.js → evidence-ZWRGNZWN.js} +3 -3
  88. package/dist/{export-cmd-QAQWWIRL.js → export-cmd-AM6SIRUW.js} +3 -3
  89. package/dist/{ga-4LGTEA6J.js → ga-6J67NDMZ.js} +3 -3
  90. package/dist/{gbp-XOLYZ4XC.js → gbp-ERTWK26L.js} +3 -3
  91. package/dist/{google-CAQDCFA6.js → google-O6VQFK4L.js} +4 -4
  92. package/dist/{google-marketing-HU5I3XPP.js → google-marketing-OEW2YGUR.js} +1 -1
  93. package/dist/{health-cmd-3PEB3M45.js → health-cmd-OPGK37MK.js} +3 -3
  94. package/dist/{history-UGUWYPOY.js → history-WTU4ETCU.js} +3 -3
  95. package/dist/index.d.ts +65 -65
  96. package/dist/index.js +24 -24
  97. package/dist/{init-DEW65BLN.js → init-XDFRSNJ6.js} +11 -11
  98. package/dist/{insights-ZC3R4ZYG.js → insights-LPEDLSEV.js} +3 -3
  99. package/dist/intelligence-service-4OO2VQ2I.js +15 -0
  100. package/dist/{journeys-W6F4BCXF.js → journeys-TWVQNRLT.js} +3 -3
  101. package/dist/{keys-ME7VRF73.js → keys-C6FPREBZ.js} +3 -3
  102. package/dist/{keyword-R3PLGSO5.js → keyword-PBSE65DK.js} +3 -3
  103. package/dist/{logs-UM7CWHYB.js → logs-62RUOAKT.js} +3 -3
  104. package/dist/{mcp-BUPP5HC6.js → mcp-P4LNENKX.js} +2 -2
  105. package/dist/mcp.js +9 -9
  106. package/dist/{measurement-plan-R4KZHJII.js → measurement-plan-HKW3IVIE.js} +5 -5
  107. package/dist/{notify-4C26D2MY.js → notify-A3I3G7NK.js} +3 -3
  108. package/dist/{organic-evidence-SLIISYHW.js → organic-evidence-OFUJBDCK.js} +3 -3
  109. package/dist/{overview-JJZZOYQU.js → overview-NSRODN2X.js} +4 -4
  110. package/dist/{project-XJH2OECP.js → project-B5G2HEAB.js} +3 -3
  111. package/dist/{query-ZWAIWIYB.js → query-UQHJVYUJ.js} +3 -3
  112. package/dist/{research-GTVWVZBI.js → research-ZWBJDLJY.js} +3 -3
  113. package/dist/{results-export-CPAWO5AV.js → results-export-FOJYT4MK.js} +3 -3
  114. package/dist/{run-RI2BMD7U.js → run-ZIUQ2TNN.js} +4 -4
  115. package/dist/{schedule-HDDWULBX.js → schedule-B5CORKGT.js} +3 -3
  116. package/dist/{search-TT3Q2BBP.js → search-2XCZKP6A.js} +3 -3
  117. package/dist/{serve-6JYPUU24.js → serve-RR6YYFKA.js} +25 -25
  118. package/dist/{session-DDESFV3N.js → session-PILSYOTX.js} +12 -12
  119. package/dist/{settings-4AYXYJVA.js → settings-Y3LVGZH4.js} +3 -3
  120. package/dist/{skills-UFMLMMY5.js → skills-6E3RVQAQ.js} +2 -2
  121. package/dist/{snapshot-KLWQGZB6.js → snapshot-RAV2HCL7.js} +3 -3
  122. package/dist/{src-6IHGEMT2.js → src-VUD6WO5N.js} +2 -2
  123. package/dist/{status-HRIUPGUM.js → status-2WCUV6C2.js} +4 -4
  124. package/dist/{technical-aeo-HKJQHMMS.js → technical-aeo-2TJEHHBR.js} +3 -3
  125. package/dist/{telemetry-IS6KZK32.js → telemetry-LQAD26UJ.js} +4 -4
  126. package/dist/{tools-ZNVQFEAX.js → tools-U6VGYZV2.js} +11 -11
  127. package/dist/{traffic-PFHFGN44.js → traffic-3TBXSHPV.js} +5 -5
  128. package/dist/{users-BSLUSU6W.js → users-2HDDA5GT.js} +3 -3
  129. package/dist/{visibility-stats-MPRNHPZW.js → visibility-stats-HSGT3OL3.js} +3 -3
  130. package/dist/{wordpress-U5XKHURL.js → wordpress-ALODIEFK.js} +3 -3
  131. package/package.json +1 -1
  132. package/assets/assets/MeasurementPropertyPage-x8f7xanT.js +0 -4
  133. package/assets/assets/ProjectPage-CG9I2-B4.js +0 -9
  134. package/assets/assets/SiteHealthSection-BvqFg3rG.js +0 -2
  135. package/assets/assets/ToneBadge-CTWpeKu8.js +0 -60
  136. package/assets/assets/index-BBNs-RhI.js +0 -60
  137. package/assets/assets/react-query-DGmY6hJa.js +0 -1
  138. package/dist/intelligence-service-XRJVXZYI.js +0 -15
@@ -5,7 +5,7 @@ import {
5
5
  AppError,
6
6
  parseWindowIn,
7
7
  resolveDateRange
8
- } from "./chunk-XEGYSZEV.js";
8
+ } from "./chunk-VPZMSV3Q.js";
9
9
 
10
10
  // src/cli-access.ts
11
11
  var CLI_ACCESS_BY_ID = Object.freeze({
@@ -332,6 +332,7 @@ var CLI_ACCESS_BY_ID = Object.freeze({
332
332
  "seo.domain-intelligence": "stored",
333
333
  "seo.keyword-metrics": "stored",
334
334
  "seo.market-rankings": "stored",
335
+ "seo.market-summary": "stored",
335
336
  "seo.operator.reconcile": "write",
336
337
  "seo.operator.task": "stored",
337
338
  "seo.overview": "stored",
@@ -6,12 +6,12 @@ import {
6
6
  import {
7
7
  createApiClient,
8
8
  runWithUsageTags
9
- } from "./chunk-XEPEMON2.js";
9
+ } from "./chunk-FDRZQH3Y.js";
10
10
  import {
11
11
  canonryMcpTools,
12
12
  mcpOutputSchema,
13
13
  toolOperationAccess
14
- } from "./chunk-37R6GTU7.js";
14
+ } from "./chunk-YIIIYNPW.js";
15
15
  import {
16
16
  PACKAGE_VERSION
17
17
  } from "./chunk-AOJU5LKX.js";
@@ -24,7 +24,7 @@ import {
24
24
  isReadOnlyKey,
25
25
  restrictedWriteScopes,
26
26
  upgradeCaveatFor
27
- } from "./chunk-XEGYSZEV.js";
27
+ } from "./chunk-VPZMSV3Q.js";
28
28
 
29
29
  // src/mcp/server.ts
30
30
  import { randomUUID } from "crypto";
@@ -258,7 +258,7 @@ var OPERATIONS_GUIDE = {
258
258
  "canonry_seo_sync",
259
259
  "canonry_seo_run_cancel"
260
260
  ],
261
- "guidance": "Read saved SEO evidence first. Preserve profile, exact domain or host, market, language, plan revision, dataset and collection date. Market rankings (canonry_seo_market_rankings) are the site's Google position for its tracked queries by market, the same queries AI visibility measures. SEO traffic and keyword metrics are third-party estimates, separate from Search Console observations and AI citation and mention coverage. Refresh requires explicit approval for the profile and work, a fresh refresh intent and an idempotency key. Hosted financial controls are internal; no credential or billing information belongs in the response."
261
+ "guidance": "Read saved SEO evidence first. Preserve profile, exact domain or host, market, language, plan revision, dataset and collection date. Market rankings (canonry_seo_market_rankings) are the site's Google position for its tracked queries by market, the same queries AI visibility measures; start with canonry_seo_market_summary for counts by outcome, and treat failed or unsearched queries as missing data. SEO traffic and keyword metrics are third-party estimates, separate from Search Console observations and AI citation and mention coverage. Refresh requires explicit approval for the profile and work, a fresh refresh intent and an idempotency key. Hosted financial controls are internal; no credential or billing information belongs in the response."
262
262
  },
263
263
  "operations": {
264
264
  "keywords": [
@@ -4,7 +4,7 @@ import {
4
4
  } from "./chunk-HGMYEDAQ.js";
5
5
  import {
6
6
  describeError
7
- } from "./chunk-XEGYSZEV.js";
7
+ } from "./chunk-VPZMSV3Q.js";
8
8
 
9
9
  // src/gsc-sitemap-submission.ts
10
10
  function dedupeGscSitemapUrls(urls) {
@@ -9,14 +9,14 @@ import {
9
9
  normalizeCloudflareWorkerEvent,
10
10
  sessionizeJourneyRequests,
11
11
  verifyRequestSignature
12
- } from "./chunk-HX3WLTZU.js";
12
+ } from "./chunk-J4CNNYRQ.js";
13
13
  import {
14
14
  currentOutcomeAttribution,
15
15
  getRequestContext,
16
16
  registerRequestContext,
17
17
  requestAuditIdentity,
18
18
  sanitizeRequestContext
19
- } from "./chunk-UXTNDZKM.js";
19
+ } from "./chunk-7SGZHGZ2.js";
20
20
  import {
21
21
  SentimentIdempotencyConflict,
22
22
  SentimentRepository,
@@ -156,7 +156,7 @@ import {
156
156
  userSessions,
157
157
  users,
158
158
  writeNegativeReviewMaxStars
159
- } from "./chunk-6DJN7HCK.js";
159
+ } from "./chunk-ARIYTYOM.js";
160
160
  import {
161
161
  ADS_ACTIVATE_SCOPE,
162
162
  ADS_ACTIVATION_ABSOLUTE_MAX_ENTITIES,
@@ -369,6 +369,7 @@ import {
369
369
  SeoAvailability,
370
370
  SeoCapabilities,
371
371
  SeoMarketRankingSearchStatuses,
372
+ SeoMarketRankingSorts,
372
373
  SeoRunStatuses,
373
374
  SeoScopeKinds,
374
375
  SeoTargetKinds,
@@ -527,6 +528,7 @@ import {
527
528
  clusterByCosine,
528
529
  coerceSkillManifest,
529
530
  compactDateToIso,
531
+ compareMarketRankingsBy,
530
532
  compareSemver,
531
533
  compareText,
532
534
  competitorAliasBlockRequestSchema,
@@ -570,6 +572,7 @@ import {
570
572
  conversionTrackingOptionsDtoSchema,
571
573
  cosineSimilarity,
572
574
  countAdsActivationManifestEntities,
575
+ countMarketRankings,
573
576
  countedLeadEventNames,
574
577
  countsAsMention,
575
578
  countsKeyEvents,
@@ -699,6 +702,7 @@ import {
699
702
  googleOAuthStartResponseSchema,
700
703
  gradedReportMonths,
701
704
  groupIsoDateRanges,
705
+ groupMarketRankings,
702
706
  gscCoverageSnapshotDtoSchema,
703
707
  gscCoverageSummaryDtoSchema,
704
708
  gscDeindexedRowSchema,
@@ -773,9 +777,12 @@ import {
773
777
  makesInstallMeasurable,
774
778
  mapWithConcurrency,
775
779
  marketPinAliasClaims,
780
+ marketRankingRow,
776
781
  matchOperationTemplate,
777
782
  matchedAliasKeys,
778
783
  matcherMatchesText,
784
+ matchesMarketRankingFilter,
785
+ matchesMarketRankingText,
779
786
  matchesMeasurementTargetUrl,
780
787
  measurementChangesQuerySchema,
781
788
  measurementChangesResponseSchema,
@@ -1048,8 +1055,12 @@ import {
1048
1055
  seoDomainIntelligenceListSchema,
1049
1056
  seoEvidenceQuerySchema,
1050
1057
  seoKeywordMetricsListSchema,
1058
+ seoMarketRankingFilterSchema,
1051
1059
  seoMarketRankingListSchema,
1052
1060
  seoMarketRankingQuerySchema,
1061
+ seoMarketRankingSortSchema,
1062
+ seoMarketRankingSummaryQuerySchema,
1063
+ seoMarketRankingSummarySchema,
1053
1064
  seoOperatorTaskSchema,
1054
1065
  seoOverviewSchema,
1055
1066
  seoProfileInputSchema,
@@ -1176,7 +1187,7 @@ import {
1176
1187
  wordpressSchemaDeployResultDtoSchema,
1177
1188
  wordpressSchemaStatusResultDtoSchema,
1178
1189
  wordpressStatusDtoSchema
1179
- } from "./chunk-XEGYSZEV.js";
1190
+ } from "./chunk-VPZMSV3Q.js";
1180
1191
 
1181
1192
  // ../api-routes/src/user-session.ts
1182
1193
  import crypto2 from "crypto";
@@ -15724,11 +15735,29 @@ async function seoRoutes(app, opts) {
15724
15735
  if (!parsed.success) throw validationError("Invalid SEO evidence selection.");
15725
15736
  const query = parsed.data;
15726
15737
  const row = selected(resolveProject(app.db, request.params.name).id, query, true);
15727
- const items = (row ? resultRows(tasks(row.id)).marketRankings : []).filter((item2) => (query.marketKey === void 0 || item2.marketKey === query.marketKey) && (query.regionKey === void 0 || item2.regionKey === query.regionKey)).sort(compareMarketRankings);
15738
+ const items = (row ? resultRows(tasks(row.id)).marketRankings.map(marketRankingRow) : []).filter((item2) => (query.marketKey === void 0 || item2.marketKey === query.marketKey) && (query.regionKey === void 0 || item2.regionKey === query.regionKey) && (query.outcome === void 0 || matchesMarketRankingFilter(item2, query.outcome)) && (query.q === void 0 || matchesMarketRankingText(item2, query.q))).sort(compareMarketRankingsBy(query.sort ?? SeoMarketRankingSorts.market));
15728
15739
  const limit = query.limit ?? 50;
15729
15740
  const offset = query.offset ?? 0;
15730
15741
  return { runId: row?.id ?? null, items: items.slice(offset, offset + limit), total: items.length, limit, offset };
15731
15742
  });
15743
+ app.get("/projects/:name/seo/market-rankings/summary", async (request) => {
15744
+ const parsed = seoMarketRankingSummaryQuerySchema.safeParse(request.query ?? {});
15745
+ if (!parsed.success) throw validationError("Invalid SEO evidence selection.");
15746
+ const query = parsed.data;
15747
+ const row = selected(resolveProject(app.db, request.params.name).id, query, true);
15748
+ const rows = (row ? resultRows(tasks(row.id)).marketRankings.map(marketRankingRow) : []).filter((item2) => (query.marketKey === void 0 || item2.marketKey === query.marketKey) && (query.regionKey === void 0 || item2.regionKey === query.regionKey));
15749
+ return {
15750
+ // The depth each search asked for; a partial search's rows say how far they reached.
15751
+ runId: row?.id ?? null,
15752
+ depth: row?.profile.rankings?.depth ?? null,
15753
+ regionKey: query.regionKey ?? null,
15754
+ marketKey: query.marketKey ?? null,
15755
+ regionLabel: query.regionKey === void 0 ? null : rows[0]?.regionLabel ?? null,
15756
+ marketLabel: query.marketKey === void 0 ? null : rows[0]?.marketLabel ?? null,
15757
+ totals: countMarketRankings(rows),
15758
+ groups: groupMarketRankings(rows, { regionKey: query.regionKey, marketKey: query.marketKey })
15759
+ };
15760
+ });
15732
15761
  }
15733
15762
 
15734
15763
  // ../api-routes/src/runs.ts
@@ -33937,6 +33966,7 @@ var SCHEMA_TABLE = {
33937
33966
  SeoDomainIntelligenceList: seoDomainIntelligenceListSchema,
33938
33967
  SeoRankedKeywordList: seoRankedKeywordListSchema,
33939
33968
  SeoMarketRankingList: seoMarketRankingListSchema,
33969
+ SeoMarketRankingSummary: seoMarketRankingSummarySchema,
33940
33970
  SentimentSummary: sentimentSummarySchema,
33941
33971
  SentimentSettings: sentimentSettingsSchema,
33942
33972
  SentimentSettingsUpdate: sentimentSettingsUpdateSchema,
@@ -35169,12 +35199,15 @@ var routeCatalog = [
35169
35199
  path: "/api/v1/projects/{name}/seo/market-rankings",
35170
35200
  summary: "Read stored market rankings",
35171
35201
  tags: ["seo"],
35172
- description: "Stored evidence only; never calls a provider. The project's position for each tracked non-brand query, searched on Google from its market's location, ordered by region, market and search text. searchStatus says how each search ended: in a completed or partial row a null rank means the site was not in the checked results (depth, which is lower when only part of the results came back); a failed or cancelled search keeps its rows with no rank.",
35202
+ description: "Stored evidence only; never calls a provider. The project's position for each tracked non-brand query, searched on Google from its market's location. searchStatus says how each search ended: in a completed or partial row a null rank means the site was not in the checked results (depth, which is lower when only part of the results came back); a failed or cancelled search keeps its rows with no rank. outcome says where each row landed (a partial search without the site is partly-checked, never not-ranked) and rivalAhead whether a tracked competitor ranks above the site.",
35173
35203
  parameters: [
35174
35204
  nameParameter,
35175
35205
  ...seoEvidenceParameters,
35176
35206
  { name: "marketKey", in: "query", description: "Only rows for this market (an Advanced market key or a Simple location label).", schema: stringSchema },
35177
- { name: "regionKey", in: "query", description: "Only rows whose market sits under this top-level group.", schema: stringSchema }
35207
+ { name: "regionKey", in: "query", description: "Only rows whose market sits under this top-level group.", schema: stringSchema },
35208
+ { name: "outcome", in: "query", description: "Only rows with this outcome. `partly-checked` is a partial search that did not reach the site, so ranks past its depth are unknown; `needs-work` is ranks 11 and deeper, not ranked or partly checked; `rival-ahead` is rows where a tracked competitor ranks above the site.", schema: { type: "string", enum: [...seoMarketRankingFilterSchema.options] } },
35209
+ { name: "q", in: "query", description: "Only rows whose query, searched text or market label contains this text, ignoring case.", schema: { type: "string", minLength: 1, maxLength: 200 } },
35210
+ { name: "sort", in: "query", description: "`market` (default): region, market, search text. `rank`: best rank first, then partly checked rows, then rows not in the results with the strongest rival first, then searches with no result. `-rank`: rows not in the results first, then partly checked rows, then the worst rank. `query` / `-query`: by query text.", schema: { type: "string", enum: [...seoMarketRankingSortSchema.options], default: "market" } }
35178
35211
  ],
35179
35212
  responses: {
35180
35213
  200: jsonResponse("SEO response.", "SeoMarketRankingList"),
@@ -35184,6 +35217,27 @@ var routeCatalog = [
35184
35217
  409: errorResponse("Selection, intent or execution identity changed.")
35185
35218
  }
35186
35219
  },
35220
+ {
35221
+ method: "get",
35222
+ path: "/api/v1/projects/{name}/seo/market-rankings/summary",
35223
+ summary: "Summarize stored market rankings by outcome",
35224
+ tags: ["seo"],
35225
+ description: "Stored evidence only; never calls a provider. Outcome counts for the selected scope (the whole profile, one region or one market) and for the groups under it: regions for the whole profile, markets within one region, none within one market. Groups come in needs-work order: most ranks 11-20, then most ranks 21 and deeper.",
35226
+ parameters: [
35227
+ nameParameter,
35228
+ { name: "profileId", in: "query", description: "Exact saved profile. Required when multiple profiles exist.", schema: stringSchema },
35229
+ { name: "runId", in: "query", description: "Exact historical refresh. Omit for latest saved evidence for the selected profile.", schema: stringSchema },
35230
+ { name: "marketKey", in: "query", description: "Summarize one market (an Advanced market key or a Simple location label).", schema: stringSchema },
35231
+ { name: "regionKey", in: "query", description: "Summarize one top-level group and the markets under it.", schema: stringSchema }
35232
+ ],
35233
+ responses: {
35234
+ 200: jsonResponse("SEO response.", "SeoMarketRankingSummary"),
35235
+ 400: errorResponse("Invalid scope or input."),
35236
+ 403: errorResponse("Insufficient authority."),
35237
+ 404: errorResponse("Project or selected evidence not found."),
35238
+ 409: errorResponse("Selection, intent or execution identity changed.")
35239
+ }
35240
+ },
35187
35241
  {
35188
35242
  method: "put",
35189
35243
  path: "/api/v1/projects/{name}/seo/profiles/{id}",
@@ -5,7 +5,7 @@ import {
5
5
  loadConfig,
6
6
  loadConfigRaw,
7
7
  saveConfigPatch
8
- } from "./chunk-UNCOK6DA.js";
8
+ } from "./chunk-MVRPFLEL.js";
9
9
  import {
10
10
  CANONRY_NPM_PACKAGE_URL,
11
11
  compareSemver,
@@ -18,7 +18,7 @@ import {
18
18
  updateCheckEnvOptOut,
19
19
  upgradeCaveatFor,
20
20
  upgradeCommandFor
21
- } from "./chunk-XEGYSZEV.js";
21
+ } from "./chunk-VPZMSV3Q.js";
22
22
 
23
23
  // src/runtime-context.ts
24
24
  function cliRuntimeContext(env = process.env, stdio = process) {
@@ -3,7 +3,7 @@ import {
3
3
  resolveCliAccess,
4
4
  resolveCliAccessForInvocation,
5
5
  windowOptions
6
- } from "./chunk-MD5PHJBX.js";
6
+ } from "./chunk-33LH4ZGF.js";
7
7
  import {
8
8
  emitJsonl
9
9
  } from "./chunk-Z7IUAJOF.js";
@@ -14,7 +14,7 @@ import {
14
14
  } from "./chunk-HGMYEDAQ.js";
15
15
  import {
16
16
  OperationAccesses
17
- } from "./chunk-XEGYSZEV.js";
17
+ } from "./chunk-VPZMSV3Q.js";
18
18
 
19
19
  // src/cli-catalog.ts
20
20
  import { createRequire } from "module";
@@ -111,7 +111,7 @@ async function dispatchRegisteredCommand(args, fallbackFormat, specs) {
111
111
  const accessValue = accessFilterFromArgs(argsWithoutHelp);
112
112
  validateAccessFilter(accessValue);
113
113
  if (fallbackFormat !== "text") {
114
- const { printCliCatalog: printCliCatalog2 } = await import("./cli-catalog-J2HUCGJL.js");
114
+ const { printCliCatalog: printCliCatalog2 } = await import("./cli-catalog-ONYERYPV.js");
115
115
  const group2 = argsWithoutHelp.find((arg) => !arg.startsWith("--"));
116
116
  printCliCatalog2(specs, fallbackFormat, group2, accessValue);
117
117
  return true;
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  USAGE_TELEMETRY_HEADERS,
3
3
  redactLogString
4
- } from "./chunk-XEGYSZEV.js";
4
+ } from "./chunk-VPZMSV3Q.js";
5
5
 
6
6
  // ../api-routes/src/request-context.ts
7
7
  import { AsyncLocalStorage } from "async_hooks";
@@ -20,7 +20,7 @@ import {
20
20
  templateLinkRatio,
21
21
  templateLinkUbiquityAvailable,
22
22
  validationError
23
- } from "./chunk-XEGYSZEV.js";
23
+ } from "./chunk-VPZMSV3Q.js";
24
24
  import {
25
25
  __export
26
26
  } from "./chunk-MLKGABMK.js";
@@ -28,7 +28,7 @@ import {
28
28
  unknownUsageObservation,
29
29
  usdToMicros,
30
30
  withRetry
31
- } from "./chunk-XEGYSZEV.js";
31
+ } from "./chunk-VPZMSV3Q.js";
32
32
 
33
33
  // ../provider-answer-services/src/core/http.ts
34
34
  var MAX_RESPONSE_BYTES = 8 * 1024 * 1024;
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  createApiClient
3
- } from "./chunk-XEPEMON2.js";
3
+ } from "./chunk-FDRZQH3Y.js";
4
4
  import {
5
5
  emitJsonl
6
6
  } from "./chunk-Z7IUAJOF.js";
@@ -19,7 +19,7 @@ import {
19
19
  formatMicros,
20
20
  formatRunErrorOneLine,
21
21
  resolveProviderInput
22
- } from "./chunk-XEGYSZEV.js";
22
+ } from "./chunk-VPZMSV3Q.js";
23
23
 
24
24
  // src/commands/run.ts
25
25
  function getClient() {