@canonry/canonry 5.19.0 → 5.19.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 (32) hide show
  1. package/assets/agent-workspace/skills/aero/SKILL.md +13 -8
  2. package/assets/agent-workspace/skills/aero/references/portfolio-analysis.md +27 -10
  3. package/assets/agent-workspace/skills/canonry/references/canonry-cli.md +4 -1
  4. package/assets/assets/{AuditHistoryPanel-C_p8jX7Q.js → AuditHistoryPanel-ddq5tdlB.js} +1 -1
  5. package/assets/assets/{BacklinksPage-jD4nOGw1.js → BacklinksPage-g57_xzTX.js} +1 -1
  6. package/assets/assets/{HistoryPage-DJGBbtBY.js → HistoryPage-C-TdCUQ2.js} +1 -1
  7. package/assets/assets/{MeasurementPropertyPage-Dmr3TVlo.js → MeasurementPropertyPage-CAADmNfw.js} +1 -1
  8. package/assets/assets/{ProjectPage-B_haCKiA.js → ProjectPage-CoBwpHmA.js} +1 -1
  9. package/assets/assets/{RunRow-BMbwR2yk.js → RunRow-BpG0Zy-x.js} +1 -1
  10. package/assets/assets/{RunsPage-D8hHakq2.js → RunsPage-DK3pb1LH.js} +1 -1
  11. package/assets/assets/{SettingsPage-QKnRcFA9.js → SettingsPage-BruiY8Zh.js} +1 -1
  12. package/assets/assets/{SiteHealthSection-CDkUXqmb.js → SiteHealthSection-De4U11Gv.js} +3 -3
  13. package/assets/assets/{TrafficPage-CMif8RlM.js → TrafficPage-BVolLXT2.js} +1 -1
  14. package/assets/assets/{TrafficSourceDetailPage-DOCTP_4-.js → TrafficSourceDetailPage-CFDb6lPD.js} +1 -1
  15. package/assets/assets/{extract-error-message-Dm8RvYE5.js → extract-error-message-Bk1RTjzo.js} +1 -1
  16. package/assets/assets/{index-lj0fuFl4.js → index-B--AA1mG.js} +44 -44
  17. package/assets/assets/{react-sigma_core.esm.min-DOPuwLtN.js → react-sigma_core.esm.min--QXVK1JS.js} +1 -1
  18. package/assets/assets/{v2-overview-adapter-C19tUcDS.js → v2-overview-adapter-CpjJPZsC.js} +1 -1
  19. package/assets/index.html +1 -1
  20. package/dist/{chunk-P2EFPLIO.js → chunk-3IAIW5KH.js} +530 -132
  21. package/dist/{chunk-YHKKCXGY.js → chunk-4WROKFN6.js} +24 -8
  22. package/dist/{chunk-SPCEXW3B.js → chunk-EJXDABGU.js} +9 -3
  23. package/dist/{chunk-GUJY3RIM.js → chunk-EJZFTNZG.js} +439 -180
  24. package/dist/{chunk-ABUO27BV.js → chunk-J3JXJIST.js} +3 -3
  25. package/dist/{chunk-QJWIOCEO.js → chunk-PGOID3LE.js} +2 -2
  26. package/dist/{chunk-WLL7Q7JD.js → chunk-SOCYTKTF.js} +195 -23
  27. package/dist/cli.js +72 -16
  28. package/dist/{demo-server-BOIBS74F.js → demo-server-BLDYKCFS.js} +4 -4
  29. package/dist/index.js +6 -6
  30. package/dist/{intelligence-service-IWR2H6OW.js → intelligence-service-3MHYLKMS.js} +2 -2
  31. package/dist/mcp.js +4 -4
  32. package/package.json +11 -11
@@ -4,14 +4,14 @@ import {
4
4
  installSkills,
5
5
  loadConfigRaw,
6
6
  saveConfigPatch
7
- } from "./chunk-SPCEXW3B.js";
7
+ } from "./chunk-EJXDABGU.js";
8
8
  import {
9
9
  PACKAGE_VERSION
10
- } from "./chunk-YHKKCXGY.js";
10
+ } from "./chunk-4WROKFN6.js";
11
11
  import {
12
12
  SKILL_MANIFEST_FILENAME,
13
13
  SkillsClients
14
- } from "./chunk-WLL7Q7JD.js";
14
+ } from "./chunk-SOCYTKTF.js";
15
15
 
16
16
  // src/skills-autosync.ts
17
17
  import fs from "fs";
@@ -5,12 +5,12 @@ import {
5
5
  siteCrawlGraphNodes,
6
6
  siteCrawlPages,
7
7
  siteCrawlSnapshots
8
- } from "./chunk-P2EFPLIO.js";
8
+ } from "./chunk-3IAIW5KH.js";
9
9
  import {
10
10
  SITE_CRAWL_GRAPH_MAX_EDGES,
11
11
  SITE_CRAWL_GRAPH_MAX_NODES,
12
12
  TEMPLATE_LINK_RATIO_THRESHOLD
13
- } from "./chunk-WLL7Q7JD.js";
13
+ } from "./chunk-SOCYTKTF.js";
14
14
 
15
15
  // src/site-crawl-graph-layout.ts
16
16
  import crypto from "crypto";
@@ -7157,25 +7157,97 @@ var measurementDemoFilterQueryShape = {
7157
7157
  location: measurementDemoLocationSchema.optional()
7158
7158
  };
7159
7159
  var measurementDemoRecommendedNameSchema = z18.string().trim().min(1);
7160
+ var MEASUREMENT_PORTFOLIO_DEFAULT_LIMIT = 4;
7161
+ var MEASUREMENT_PORTFOLIO_ROW_EVIDENCE_LIMIT = 5;
7162
+ var MEASUREMENT_PORTFOLIO_ANSWER_SOURCES_LIMIT = 10;
7163
+ var MEASUREMENT_PORTFOLIO_TIE_NOTE = "tied Properties are ordered by name, not ranked";
7160
7164
  var measurementPortfolioSummaryQuerySchema = z18.object({
7161
7165
  runId: measurementDemoFilterQueryShape.runId,
7162
7166
  groupKey: measurementV2StableKeySchema.optional(),
7163
7167
  queryClass: measurementQueryClassFilterSchema.default("non-brand"),
7164
7168
  provider: measurementDemoFilterQueryShape.provider,
7165
7169
  location: measurementDemoFilterQueryShape.location,
7166
- limit: z18.number().int().positive().max(50).optional()
7170
+ /** Caps every list in the response (Property rows, both mention rankings, markets). Defaults to 4. */
7171
+ limit: z18.number().int().positive().max(50).optional(),
7172
+ /**
7173
+ * Off by default: `markets` holds one level only, the top-level markets (or
7174
+ * the selected group's direct children), worst-first and capped at `limit`.
7175
+ * True returns every market in scope at every level, uncapped, as the
7176
+ * roll-up did before it was levelled.
7177
+ */
7178
+ includeNestedMarkets: z18.boolean().optional()
7179
+ }).strict();
7180
+ var measurementPortfolioMetroSchema = z18.object({
7181
+ groupKey: measurementV2StableKeySchema,
7182
+ label: measurementDemoLabelSchema
7183
+ }).strict();
7184
+ var measurementPortfolioPropertyContextShape = {
7185
+ /** The top-level group holding this Property; null when it is in none. */
7186
+ metro: measurementPortfolioMetroSchema.nullable(),
7187
+ /** Further top-level groups holding the same Property. Present only when there are any. */
7188
+ otherMetros: z18.array(measurementPortfolioMetroSchema).min(1).optional(),
7189
+ /** Labels of every nested (non-top-level) group holding this Property, shallowest first. */
7190
+ submarkets: z18.array(measurementDemoLabelSchema),
7191
+ queries: measurementDemoCountSchema
7192
+ };
7193
+ var measurementPortfolioCountedNameSchema = z18.object({
7194
+ name: measurementDemoRecommendedNameSchema,
7195
+ /** Answers that wrote this name. */
7196
+ answers: measurementDemoCountSchema
7197
+ }).strict();
7198
+ var measurementPortfolioRecommendedInsteadSchema = z18.object({
7199
+ name: measurementDemoRecommendedNameSchema,
7200
+ /** Answers that wrote this name, one per answer however it spells it: the same count as `namedInsteadInAnswerText[].answers`. */
7201
+ occurrences: measurementDemoCountSchema
7202
+ }).strict();
7203
+ var measurementPortfolioCountedDomainSchema = z18.object({
7204
+ domain: z18.string().trim().min(1),
7205
+ /** Answers citing at least one URL on this domain. */
7206
+ answers: measurementDemoCountSchema
7167
7207
  }).strict();
7168
7208
  var measurementPortfolioWeakestPropertySchema = measurementDemoPropertySchema.extend({
7209
+ ...measurementPortfolioPropertyContextShape,
7169
7210
  mentionCoverage: measurementMetricValueSchema,
7170
7211
  citationCoverage: measurementMetricValueSchema,
7171
7212
  flags: measurementDemoCountSchema,
7172
- recommendedInstead: z18.array(z18.object({
7173
- name: measurementDemoRecommendedNameSchema,
7174
- occurrences: measurementDemoCountSchema
7175
- }).strict()).max(5),
7176
- recommendedInsteadTotal: measurementDemoCountSchema,
7177
- recommendedInsteadTruncated: z18.boolean()
7213
+ /**
7214
+ * Names WRITTEN IN THE ANSWER TEXT of this Property's answers that neither
7215
+ * named nor cited it, counted by answer. These are mentions, never
7216
+ * citations: a name here says nothing about which sources were linked.
7217
+ * Supersedes the deprecated `recommendedInstead`, whose name read as a
7218
+ * citation.
7219
+ */
7220
+ namedInsteadInAnswerText: z18.array(measurementPortfolioCountedNameSchema).max(MEASUREMENT_PORTFOLIO_ROW_EVIDENCE_LIMIT),
7221
+ /** Distinct names across those answers; more than returned means the list was cut. */
7222
+ namedInsteadInAnswerTextTotal: measurementDemoCountSchema,
7223
+ /**
7224
+ * Domains cited by this Property's stored answers in this run and class,
7225
+ * every engine included: each answer's stored domains plus the hosts of its
7226
+ * captured source URLs, and answers whose text was not captured count too.
7227
+ */
7228
+ citedDomains: z18.array(measurementPortfolioCountedDomainSchema).max(MEASUREMENT_PORTFOLIO_ROW_EVIDENCE_LIMIT),
7229
+ /** Distinct cited domains; more than returned means the list was cut. */
7230
+ citedDomainsTotal: measurementDemoCountSchema,
7231
+ /**
7232
+ * Deprecated: read `namedInsteadInAnswerText`. The same names in the same
7233
+ * order, kept for existing consumers. `occurrences` counts answers, one per
7234
+ * answer however it spells the name, exactly as `answers` does there.
7235
+ */
7236
+ recommendedInstead: z18.array(measurementPortfolioRecommendedInsteadSchema).max(MEASUREMENT_PORTFOLIO_ROW_EVIDENCE_LIMIT).meta({ deprecated: true, description: "Deprecated: read namedInsteadInAnswerText, which carries the same names in the same order. occurrences counts answers, exactly as answers does there." }),
7237
+ /** Deprecated: read `namedInsteadInAnswerTextTotal`, which it always equals. */
7238
+ recommendedInsteadTotal: measurementDemoCountSchema.meta({ deprecated: true, description: "Deprecated: read namedInsteadInAnswerTextTotal, which it always equals." }),
7239
+ /** Deprecated: true when `namedInsteadInAnswerTextTotal` exceeds the names returned. */
7240
+ recommendedInsteadTruncated: z18.boolean().meta({ deprecated: true, description: "Deprecated: true when namedInsteadInAnswerTextTotal exceeds the names returned in namedInsteadInAnswerText." })
7178
7241
  }).strict().superRefine((row, ctx) => {
7242
+ if (row.namedInsteadInAnswerText.length > row.namedInsteadInAnswerTextTotal) {
7243
+ ctx.addIssue({ code: z18.ZodIssueCode.custom, path: ["namedInsteadInAnswerTextTotal"], message: "Total cannot be smaller than the returned names" });
7244
+ }
7245
+ if (row.citedDomains.length > row.citedDomainsTotal) {
7246
+ ctx.addIssue({ code: z18.ZodIssueCode.custom, path: ["citedDomainsTotal"], message: "Total cannot be smaller than the returned domains" });
7247
+ }
7248
+ if (row.recommendedInsteadTotal !== row.namedInsteadInAnswerTextTotal) {
7249
+ ctx.addIssue({ code: z18.ZodIssueCode.custom, path: ["recommendedInsteadTotal"], message: "The deprecated total must equal namedInsteadInAnswerTextTotal" });
7250
+ }
7179
7251
  if (row.recommendedInstead.length > row.recommendedInsteadTotal) {
7180
7252
  ctx.addIssue({ code: z18.ZodIssueCode.custom, path: ["recommendedInsteadTotal"], message: "Total cannot be smaller than the returned replacements" });
7181
7253
  }
@@ -7183,24 +7255,46 @@ var measurementPortfolioWeakestPropertySchema = measurementDemoPropertySchema.ex
7183
7255
  ctx.addIssue({ code: z18.ZodIssueCode.custom, path: ["recommendedInsteadTruncated"], message: "Truncation must agree with the replacement total" });
7184
7256
  }
7185
7257
  });
7258
+ var measurementPortfolioWeakestTieSchema = z18.object({
7259
+ count: z18.number().int().min(2),
7260
+ mentionRate: z18.number(),
7261
+ citationRate: z18.number(),
7262
+ note: z18.literal(MEASUREMENT_PORTFOLIO_TIE_NOTE)
7263
+ }).strict();
7264
+ var measurementPortfolioAnswerSourcesSchema = z18.object({
7265
+ properties: measurementDemoCountSchema,
7266
+ answers: measurementDemoCountSchema,
7267
+ domains: z18.array(measurementPortfolioCountedDomainSchema).max(MEASUREMENT_PORTFOLIO_ANSWER_SOURCES_LIMIT),
7268
+ domainTotal: measurementDemoCountSchema
7269
+ }).strict().superRefine((sources, ctx) => {
7270
+ if (sources.domains.length > sources.domainTotal) {
7271
+ ctx.addIssue({ code: z18.ZodIssueCode.custom, path: ["domainTotal"], message: "Total cannot be smaller than the returned domains" });
7272
+ }
7273
+ if (sources.domains.some((row) => row.answers > sources.answers)) {
7274
+ ctx.addIssue({ code: z18.ZodIssueCode.custom, path: ["domains"], message: "A domain cannot be cited by more answers than the basis holds" });
7275
+ }
7276
+ });
7186
7277
  var measurementPortfolioMarketSchema = z18.object({
7187
7278
  groupKey: measurementV2StableKeySchema,
7188
7279
  label: measurementDemoLabelSchema,
7280
+ /** Null for a top-level market. */
7281
+ parentGroupKey: measurementV2StableKeySchema.nullable(),
7282
+ /** Direct child markets; read one with `groupKey` to list them. */
7283
+ childMarketCount: measurementDemoCountSchema,
7189
7284
  propertyCount: measurementDemoCountSchema,
7190
7285
  propertiesMentioned: measurementMetricValueSchema,
7191
7286
  mentionCoverage: measurementMetricValueSchema,
7192
7287
  citationCoverage: measurementMetricValueSchema
7193
7288
  }).strict();
7289
+ var measurementPortfolioRankedPropertySchema = measurementDemoPropertySchema.extend({
7290
+ ...measurementPortfolioPropertyContextShape,
7291
+ mentionCoverage: measurementMetricValueSchema.options[0],
7292
+ citationCoverage: measurementMetricValueSchema
7293
+ }).strict();
7194
7294
  var measurementPortfolioMentionRankingSchema = z18.object({
7195
7295
  eligiblePropertyCount: measurementDemoCountSchema,
7196
- strongest: z18.array(measurementDemoPropertySchema.extend({
7197
- mentionCoverage: measurementMetricValueSchema.options[0],
7198
- citationCoverage: measurementMetricValueSchema
7199
- }).strict()).max(50),
7200
- weakest: z18.array(measurementDemoPropertySchema.extend({
7201
- mentionCoverage: measurementMetricValueSchema.options[0],
7202
- citationCoverage: measurementMetricValueSchema
7203
- }).strict()).max(50),
7296
+ strongest: z18.array(measurementPortfolioRankedPropertySchema).max(50),
7297
+ weakest: z18.array(measurementPortfolioRankedPropertySchema).max(50),
7204
7298
  /** All excluded Properties in this scope, independent of the ranked list limit. */
7205
7299
  excluded: z18.array(measurementDemoPropertySchema.extend({
7206
7300
  reason: measurementMetricUnavailableReasonSchema
@@ -7217,23 +7311,37 @@ var measurementPortfolioSummaryResponseSchema = z18.object({
7217
7311
  }).strict(),
7218
7312
  measurement: measurementDemoRunMetadataSchema,
7219
7313
  queryClass: measurementQueryClassFilterSchema,
7314
+ /** Engines behind the displayed answers, after any provider filter. Empty before a run completes. */
7315
+ engines: z18.array(providerNameSchema),
7220
7316
  metrics: z18.object({
7221
7317
  propertiesMentioned: measurementMetricValueSchema,
7222
7318
  mentionCoverage: measurementMetricValueSchema,
7223
7319
  citationCoverage: measurementMetricValueSchema
7224
7320
  }).strict(),
7225
7321
  weakestProperties: z18.array(measurementPortfolioWeakestPropertySchema),
7322
+ /** Set when two or more Properties share the weakest row's rates; null otherwise. */
7323
+ tiedAtWeakest: measurementPortfolioWeakestTieSchema.nullable(),
7324
+ /** Null before a run completes. */
7325
+ weakestAnswerSources: measurementPortfolioAnswerSourcesSchema.nullable(),
7226
7326
  /** Descriptive mention ranking, using the response queryClass and scope; aggregate unavailability does not invalidate it. */
7227
7327
  mentionRanking: measurementPortfolioMentionRankingSchema,
7228
7328
  /**
7229
- * Every named market, worst-first. Empty when the request already narrowed to
7230
- * one group (a roll-up would only restate the scope) and when the plan defines
7231
- * no groups. Additive field.
7329
+ * Markets worst-first. By default one level: the top-level markets, or the
7330
+ * selected group's direct children when `groupKey` is set (empty when it has
7331
+ * none), capped at `limit`. `includeNestedMarkets` returns every market in
7332
+ * scope at every level, uncapped. Empty when the plan defines no groups.
7232
7333
  */
7233
7334
  markets: z18.array(measurementPortfolioMarketSchema),
7335
+ /** Markets at the returned level before `limit`; more than returned means the list was cut. */
7336
+ totalMarkets: measurementDemoCountSchema,
7337
+ marketsTruncated: z18.boolean(),
7234
7338
  totalProperties: measurementDemoCountSchema,
7235
7339
  truncated: z18.boolean()
7236
- }).strict();
7340
+ }).strict().superRefine((response, ctx) => {
7341
+ if (response.marketsTruncated !== response.markets.length < response.totalMarkets) {
7342
+ ctx.addIssue({ code: z18.ZodIssueCode.custom, path: ["marketsTruncated"], message: "Market truncation must agree with the market total" });
7343
+ }
7344
+ });
7237
7345
  var measurementPropertyQuestionsQuerySchema = z18.object({
7238
7346
  targetKey: measurementV2StableKeySchema,
7239
7347
  runId: measurementDemoFilterQueryShape.runId,
@@ -13055,6 +13163,12 @@ var sourceRankEntrySchema = z40.object({
13055
13163
  count: z40.number().int(),
13056
13164
  /** Share of the list's `totalCitedSlots`, 0..1 (4dp). */
13057
13165
  percentage: z40.number(),
13166
+ /**
13167
+ * Share of the list's `answerTotal` (every answer in scope, including answers
13168
+ * that cited nothing) that cite this domain, 0..1 (4dp). Optional only so an
13169
+ * older server's response still parses.
13170
+ */
13171
+ answerShare: z40.number().optional(),
13058
13172
  category: sourceCategorySchema,
13059
13173
  label: z40.string(),
13060
13174
  surfaceClass: surfaceClassSchema
@@ -13068,8 +13182,12 @@ var surfaceClassCountSchema = z40.object({
13068
13182
  domainCount: z40.number().int()
13069
13183
  });
13070
13184
  var rankedSourceListSchema = z40.object({
13071
- /** Total cited slots (grounding citations) counted in this scope. */
13185
+ /** Total cited slots in this scope: one per (answer, cited domain) pair. */
13072
13186
  totalCitedSlots: z40.number().int(),
13187
+ /** Answers in this scope, including answers that cited nothing. Denominator of `answerShare`. */
13188
+ answerTotal: z40.number().int().optional(),
13189
+ /** Answers in this scope whose stored source list names at least one domain. */
13190
+ answersWithSources: z40.number().int().optional(),
13073
13191
  /** Distinct domains in this scope. */
13074
13192
  domainTotal: z40.number().int(),
13075
13193
  /** Ranked domains, desc by count; truncated to the applied limit if any. */
@@ -13081,17 +13199,57 @@ var rankedSourceListSchema = z40.object({
13081
13199
  /** Surface-class roll-up over the FULL scope (not just `entries`). */
13082
13200
  bySurfaceClass: z40.array(surfaceClassCountSchema)
13083
13201
  });
13202
+ var sourceBreakdownQueryClassBasisSchema = z40.enum(["measurement-plan", "query-text"]);
13203
+ var sourceBreakdownQuerySchema = z40.object({
13204
+ /** One stored answer-visibility run. Omit to pool every run in the window. */
13205
+ runId: z40.string().trim().min(1).optional(),
13206
+ /**
13207
+ * Branded or non-brand answers only. With an active v2 measurement plan the
13208
+ * class comes from each run's frozen plan assignments; otherwise from the
13209
+ * project's brand-name classifier over the query text. `all` (the default)
13210
+ * pools both classes.
13211
+ */
13212
+ queryClass: queryClassFilterSchema.optional(),
13213
+ /** `false` omits the per-query breakdown (`byQuery`), which is large. Defaults to `true`. */
13214
+ includeByQuery: z40.enum(["true", "false", "1", "0"]).optional()
13215
+ });
13084
13216
  var sourceBreakdownDtoSchema = z40.object({
13085
- overall: z40.array(sourceCategoryCountSchema),
13086
- byQuery: z40.record(z40.string(), z40.array(sourceCategoryCountSchema)),
13087
13217
  /** Full ranked + classified cited-domain list across all providers (#675). */
13088
13218
  ranked: rankedSourceListSchema,
13089
13219
  /** Per-provider ranked + classified breakdown, keyed by provider name (#675). */
13090
13220
  byProvider: z40.record(z40.string(), rankedSourceListSchema),
13221
+ /**
13222
+ * Providers that answered in scope but whose answers name no resolvable
13223
+ * source. They are absent from `byProvider`; listed here so their absence is
13224
+ * never read as missing data.
13225
+ */
13226
+ providersWithoutSources: z40.array(z40.string()).optional(),
13227
+ /** Answers in scope after every filter, across all providers. */
13228
+ answerTotal: z40.number().int().optional(),
13229
+ /** Runs pooled into this response. More than one means several sweeps are pooled. */
13230
+ runCount: z40.number().int().optional(),
13231
+ /**
13232
+ * Answers the `queryClass` filter could not place in either class (a run with
13233
+ * no frozen v2 plan, an answer with no plan execution, or no query text).
13234
+ * They are excluded from every count. Zero when no class filter is applied.
13235
+ */
13236
+ unclassifiedAnswers: z40.number().int().optional(),
13237
+ /** Echo of the applied filters. */
13238
+ filters: z40.object({
13239
+ runId: z40.string().nullable(),
13240
+ queryClass: queryClassFilterSchema,
13241
+ /** Null when `queryClass` is `all` and no classification was applied. */
13242
+ queryClassBasis: z40.union([sourceBreakdownQueryClassBasisSchema, z40.null()]),
13243
+ includeByQuery: z40.boolean()
13244
+ }).optional(),
13091
13245
  runId: z40.string(),
13092
13246
  window: metricsWindowSchema,
13093
13247
  /** Applied ranked-list limit; null when the full list is returned. */
13094
- limit: z40.number().int().nullable()
13248
+ limit: z40.number().int().nullable(),
13249
+ /** Legacy category breakdown (top 5 domains per category). */
13250
+ overall: z40.array(sourceCategoryCountSchema),
13251
+ /** Per-query category breakdown keyed by current query text. Omitted with `includeByQuery=false`. */
13252
+ byQuery: z40.record(z40.string(), z40.array(sourceCategoryCountSchema)).optional()
13095
13253
  });
13096
13254
  var competitorLandscapeSurfaceClassSchema = z40.enum([
13097
13255
  "own",
@@ -13172,10 +13330,14 @@ var competitorLandscapeEvidenceSchema = z40.object({
13172
13330
  excludedNonCompletedResults: z40.number().int().nonnegative()
13173
13331
  }).strict();
13174
13332
  var COMPETITOR_LANDSCAPE_MODEL_GROUP_LIMIT = 50;
13333
+ var COMPETITOR_LANDSCAPE_OBSERVED_NAME_LIMIT = 50;
13175
13334
  var competitorLandscapeModelGroupSchema = z40.object({
13176
13335
  ...shareOfVoiceContextFields,
13177
13336
  comparison: z40.array(z40.object({ domain: z40.string(), mentions: z40.number().int().nonnegative() })).optional(),
13337
+ /** Names written in the answer text (not cited sources), top `COMPETITOR_LANDSCAPE_OBSERVED_NAME_LIMIT` by answer count. */
13178
13338
  observedNames: z40.array(z40.object({ name: z40.string(), answerCount: z40.number().int().nonnegative() })).optional(),
13339
+ /** Distinct observed names before the cap. Greater than `observedNames.length` when the list was cut. */
13340
+ observedNamesTotal: z40.number().int().nonnegative().optional(),
13179
13341
  provider: z40.string().trim().min(1),
13180
13342
  /** Null preserves historical observations with unknown requested model identity. */
13181
13343
  model: modelIdSchema.nullable(),
@@ -13200,7 +13362,10 @@ var competitorLandscapeModelComparisonSchema = z40.object({
13200
13362
  var competitorLandscapeResponseSchema = z40.object({
13201
13363
  ...shareOfVoiceContextFields,
13202
13364
  comparison: z40.array(z40.object({ domain: z40.string(), mentions: z40.number().int().nonnegative() })).optional(),
13365
+ /** Names written in the answer text (not cited sources), top `COMPETITOR_LANDSCAPE_OBSERVED_NAME_LIMIT` by answer count. */
13203
13366
  observedNames: z40.array(z40.object({ name: z40.string(), answerCount: z40.number().int().nonnegative() })).optional(),
13367
+ /** Distinct observed names before the cap. Greater than `observedNames.length` when the list was cut. */
13368
+ observedNamesTotal: z40.number().int().nonnegative().optional(),
13204
13369
  window: metricsWindowSchema,
13205
13370
  scope: competitorLandscapeScopeSchema,
13206
13371
  project: competitorLandscapeRowSchema,
@@ -19477,6 +19642,7 @@ export {
19477
19642
  effectiveBrandNames,
19478
19643
  projectConfigSchema,
19479
19644
  resolveConfigSpecQueries,
19645
+ queryClassFilterSchema,
19480
19646
  compileQueryClassifier,
19481
19647
  MEASUREMENT_PLAN_V2_SCHEMA_VERSION,
19482
19648
  measurementV2UsageEdgeKey,
@@ -19550,6 +19716,10 @@ export {
19550
19716
  buildMeasurementRunManifestV1,
19551
19717
  measurementReportResponseSchema,
19552
19718
  measurementPropertyEvidenceResponseSchema,
19719
+ MEASUREMENT_PORTFOLIO_DEFAULT_LIMIT,
19720
+ MEASUREMENT_PORTFOLIO_ROW_EVIDENCE_LIMIT,
19721
+ MEASUREMENT_PORTFOLIO_ANSWER_SOURCES_LIMIT,
19722
+ MEASUREMENT_PORTFOLIO_TIE_NOTE,
19553
19723
  measurementPortfolioSummaryQuerySchema,
19554
19724
  measurementPortfolioSummaryResponseSchema,
19555
19725
  measurementPropertyQuestionsQuerySchema,
@@ -19912,9 +20082,11 @@ export {
19912
20082
  normalizeModelId,
19913
20083
  modelIdsEquivalent,
19914
20084
  brandMetricsDtoSchema,
20085
+ sourceBreakdownQuerySchema,
19915
20086
  sourceBreakdownDtoSchema,
19916
20087
  competitorLandscapeQuerySchema,
19917
20088
  COMPETITOR_LANDSCAPE_MODEL_GROUP_LIMIT,
20089
+ COMPETITOR_LANDSCAPE_OBSERVED_NAME_LIMIT,
19918
20090
  competitorLandscapeResponseSchema,
19919
20091
  parseWindow,
19920
20092
  windowCutoff,
package/dist/cli.js CHANGED
@@ -35,11 +35,11 @@ import {
35
35
  trackCliCommandFinished,
36
36
  trackEvent,
37
37
  waitForServerRuntimeStartup
38
- } from "./chunk-GUJY3RIM.js";
38
+ } from "./chunk-EJZFTNZG.js";
39
39
  import {
40
40
  autoSyncSkills,
41
41
  formatAutoSyncNotice
42
- } from "./chunk-ABUO27BV.js";
42
+ } from "./chunk-J3JXJIST.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-SPCEXW3B.js";
59
+ } from "./chunk-EJXDABGU.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-QJWIOCEO.js";
65
+ import "./chunk-PGOID3LE.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-YHKKCXGY.js";
77
+ } from "./chunk-4WROKFN6.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-P2EFPLIO.js";
92
+ } from "./chunk-3IAIW5KH.js";
93
93
  import {
94
94
  AdsDeliverySnapshotStatuses,
95
95
  AdsHistoricalCampaignRollupStatuses,
@@ -165,6 +165,7 @@ import {
165
165
  normalizeProjectAliases,
166
166
  normalizeTelemetryStatus,
167
167
  notificationEventSchema,
168
+ queryClassFilterSchema,
168
169
  queryTrackingCommitRequestSchema,
169
170
  queryTrackingPreviewRequestSchema,
170
171
  reportUnattributedAnswers,
@@ -176,7 +177,7 @@ import {
176
177
  snapshotProviderModeSchema,
177
178
  visibilityReportRequestSchema,
178
179
  winnabilityClassSchema
179
- } from "./chunk-WLL7Q7JD.js";
180
+ } from "./chunk-SOCYTKTF.js";
180
181
 
181
182
  // src/cli.ts
182
183
  import { pathToFileURL } from "url";
@@ -441,7 +442,7 @@ function parseDemoTrustedProxies(values) {
441
442
  async function demoCommand(options) {
442
443
  const { host, port } = parseDemoListenOptions(options);
443
444
  const trustProxy = parseDemoTrustedProxies(options.trustProxy);
444
- const { createDemoServer } = await import("./demo-server-BOIBS74F.js");
445
+ const { createDemoServer } = await import("./demo-server-BLDYKCFS.js");
445
446
  const app = await createDemoServer({ trustProxy });
446
447
  let stopping = false;
447
448
  const stop = () => {
@@ -7808,7 +7809,8 @@ function printCompetitorLandscape(data) {
7808
7809
  `Evidence: ${data.evidence.answeredResults} answer-text result(s), ${data.evidence.sourceResults} source result(s); excluded: ${data.evidence.excludedProbeResults} probe, ${data.evidence.excludedNonCompletedResults} non-completed.`
7809
7810
  );
7810
7811
  if (data.observedNames?.length) {
7811
- console.log("Names observed in answers (not a comparison set):");
7812
+ const total = data.observedNamesTotal ?? data.observedNames.length;
7813
+ console.log(total > data.observedNames.length ? `Names observed in answers (not a comparison set), top ${data.observedNames.length} of ${total}:` : "Names observed in answers (not a comparison set):");
7812
7814
  for (const row of data.observedNames) console.log(` ${row.name} \xB7 ${row.answerCount} answers`);
7813
7815
  }
7814
7816
  if (data.modelComparison) printModelComparison(data.modelComparison, data.filters.queryClass);
@@ -11435,16 +11437,46 @@ Source Origin Breakdown`);
11435
11437
  function getClient18() {
11436
11438
  return createApiClient();
11437
11439
  }
11440
+ var SOURCES_USAGE = "canonry sources <project> [--rank] [--limit N] [--by-provider] [--window 7d|30d|90d|all] [--query-class all|branded|non-brand] [--run-id <id>] [--include-by-query true|false] [--format json|jsonl]";
11441
+ function parseSourcesQueryClass(value) {
11442
+ if (value === void 0) return void 0;
11443
+ const parsed = queryClassFilterSchema.safeParse(value);
11444
+ if (parsed.success) return parsed.data;
11445
+ const message = `--query-class must be one of ${queryClassFilterSchema.options.join(", ")}`;
11446
+ throw usageError(`Error: ${message}
11447
+ Usage: ${SOURCES_USAGE}`, {
11448
+ message,
11449
+ details: { command: "sources", usage: SOURCES_USAGE, option: "query-class", value }
11450
+ });
11451
+ }
11452
+ function parseSourcesIncludeByQuery(value) {
11453
+ if (value === void 0) return void 0;
11454
+ if (value === "true") return true;
11455
+ if (value === "false") return false;
11456
+ const message = "--include-by-query must be true or false";
11457
+ throw usageError(`Error: ${message}
11458
+ Usage: ${SOURCES_USAGE}`, {
11459
+ message,
11460
+ details: { command: "sources", usage: SOURCES_USAGE, option: "include-by-query", value }
11461
+ });
11462
+ }
11438
11463
  var pct = (n) => `${(n * 100).toFixed(1)}%`;
11439
11464
  async function showSources(project, options) {
11440
11465
  if (options.limit !== void 0 && (!Number.isInteger(options.limit) || options.limit <= 0)) {
11441
- throw usageError("Error: --limit must be a positive integer\nUsage: canonry sources <project> [--rank] [--limit N] [--by-provider] [--window 7d|30d|90d|all] [--format json|jsonl]", {
11466
+ throw usageError(`Error: --limit must be a positive integer
11467
+ Usage: ${SOURCES_USAGE}`, {
11442
11468
  message: "--limit must be a positive integer",
11443
11469
  details: { command: "sources", option: "limit", value: options.limit }
11444
11470
  });
11445
11471
  }
11446
11472
  const client = getClient18();
11447
- const data = await client.getAnalyticsSources(project, { window: options.window, limit: options.limit });
11473
+ const data = await client.getAnalyticsSources(project, {
11474
+ window: options.window,
11475
+ limit: options.limit,
11476
+ ...options.runId === void 0 ? {} : { runId: options.runId },
11477
+ ...options.queryClass === void 0 ? {} : { queryClass: options.queryClass },
11478
+ ...options.includeByQuery === void 0 ? {} : { includeByQuery: options.includeByQuery }
11479
+ });
11448
11480
  if (options.format === "jsonl") {
11449
11481
  emitJsonl(data.ranked.entries.map((e) => ({ project, ...e })));
11450
11482
  return;
@@ -11459,6 +11491,8 @@ function printSourceRankings(data, options) {
11459
11491
  console.log(`
11460
11492
  Source Rankings (${data.window})`);
11461
11493
  console.log("\u2500".repeat(50));
11494
+ const scope = describeScope(data);
11495
+ if (scope) console.log(` ${scope}`);
11462
11496
  if (data.ranked.totalCitedSlots === 0) {
11463
11497
  console.log(" No source data available");
11464
11498
  return;
@@ -11476,8 +11510,25 @@ Source Rankings (${data.window})`);
11476
11510
  ${provider} (${list.totalCitedSlots} cited slots):`);
11477
11511
  printRankedEntries(list, " ");
11478
11512
  }
11513
+ for (const provider of data.providersWithoutSources ?? []) {
11514
+ console.log(`
11515
+ ${provider}: answered, but no answer named a source`);
11516
+ }
11479
11517
  }
11480
11518
  }
11519
+ function describeScope(data) {
11520
+ const parts = [];
11521
+ if (data.answerTotal !== void 0) parts.push(`${data.answerTotal} answers`);
11522
+ if (data.filters?.runId) parts.push(`run ${data.filters.runId}`);
11523
+ else if (data.runCount !== void 0) parts.push(`${data.runCount} ${data.runCount === 1 ? "run" : "runs"} pooled`);
11524
+ if (data.filters) {
11525
+ parts.push(data.filters.queryClass === "all" ? "branded and non-brand pooled" : `${data.filters.queryClass} queries only`);
11526
+ }
11527
+ if (data.unclassifiedAnswers) {
11528
+ parts.push(`${data.unclassifiedAnswers} unclassified ${data.unclassifiedAnswers === 1 ? "answer" : "answers"} excluded`);
11529
+ }
11530
+ return parts.length > 0 ? parts.join(" \xB7 ") : null;
11531
+ }
11481
11532
  function printSurfaceClasses(list) {
11482
11533
  for (const c of list.bySurfaceClass) {
11483
11534
  const noun = c.domainCount === 1 ? "domain" : "domains";
@@ -11840,25 +11891,30 @@ var OPERATOR_CLI_COMMANDS = [
11840
11891
  },
11841
11892
  {
11842
11893
  path: ["sources"],
11843
- usage: "canonry sources <project> [--rank] [--limit N] [--by-provider] [--window 7d|30d|90d|all] [--format json|jsonl]",
11894
+ usage: SOURCES_USAGE,
11844
11895
  options: {
11845
11896
  rank: { type: "boolean", default: false },
11846
11897
  "by-provider": { type: "boolean", default: false },
11847
11898
  limit: stringOption(),
11848
- window: stringOption()
11899
+ window: stringOption(),
11900
+ "query-class": stringOption(),
11901
+ "run-id": stringOption(),
11902
+ "include-by-query": stringOption()
11849
11903
  },
11850
11904
  run: async (input) => {
11851
- const usage = "canonry sources <project> [--rank] [--limit N] [--by-provider] [--window 7d|30d|90d|all] [--format json|jsonl]";
11852
- const project = requireProject(input, "sources", usage);
11905
+ const project = requireProject(input, "sources", SOURCES_USAGE);
11853
11906
  await showSources(project, {
11854
11907
  rank: getBoolean(input.values, "rank"),
11855
11908
  byProvider: getBoolean(input.values, "by-provider"),
11856
11909
  limit: parseIntegerOption(input, "limit", {
11857
11910
  message: "--limit must be an integer",
11858
- usage,
11911
+ usage: SOURCES_USAGE,
11859
11912
  command: "sources"
11860
11913
  }),
11861
11914
  window: getString(input.values, "window"),
11915
+ runId: getString(input.values, "run-id"),
11916
+ queryClass: parseSourcesQueryClass(getString(input.values, "query-class")),
11917
+ includeByQuery: parseSourcesIncludeByQuery(getString(input.values, "include-by-query")),
11862
11918
  format: input.format
11863
11919
  });
11864
11920
  }
@@ -4,11 +4,11 @@ import {
4
4
  import {
5
5
  layoutSiteCrawlGraphInput,
6
6
  persistSiteCrawlGraphLayout
7
- } from "./chunk-QJWIOCEO.js";
7
+ } from "./chunk-PGOID3LE.js";
8
8
  import {
9
9
  PACKAGE_VERSION,
10
10
  canonryMcpTools
11
- } from "./chunk-YHKKCXGY.js";
11
+ } from "./chunk-4WROKFN6.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-P2EFPLIO.js";
87
+ } from "./chunk-3IAIW5KH.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-WLL7Q7JD.js";
111
+ } from "./chunk-SOCYTKTF.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-GUJY3RIM.js";
6
+ } from "./chunk-EJZFTNZG.js";
7
7
  import {
8
8
  loadConfig
9
- } from "./chunk-SPCEXW3B.js";
10
- import "./chunk-QJWIOCEO.js";
11
- import "./chunk-YHKKCXGY.js";
12
- import "./chunk-P2EFPLIO.js";
13
- import "./chunk-WLL7Q7JD.js";
9
+ } from "./chunk-EJXDABGU.js";
10
+ import "./chunk-PGOID3LE.js";
11
+ import "./chunk-4WROKFN6.js";
12
+ import "./chunk-3IAIW5KH.js";
13
+ import "./chunk-SOCYTKTF.js";
14
14
  export {
15
15
  GoogleMarketingRuntimeError,
16
16
  createGoogleMarketingCredentialStore,
@@ -1,8 +1,8 @@
1
1
  import {
2
2
  HISTORY_WINDOW_RUNS,
3
3
  IntelligenceService
4
- } from "./chunk-P2EFPLIO.js";
5
- import "./chunk-WLL7Q7JD.js";
4
+ } from "./chunk-3IAIW5KH.js";
5
+ import "./chunk-SOCYTKTF.js";
6
6
  export {
7
7
  HISTORY_WINDOW_RUNS,
8
8
  IntelligenceService
package/dist/mcp.js CHANGED
@@ -1,15 +1,15 @@
1
1
  import {
2
2
  autoSyncSkills
3
- } from "./chunk-ABUO27BV.js";
3
+ } from "./chunk-J3JXJIST.js";
4
4
  import {
5
5
  createApiClient,
6
6
  createCanonryMcpServer
7
- } from "./chunk-SPCEXW3B.js";
8
- import "./chunk-YHKKCXGY.js";
7
+ } from "./chunk-EJXDABGU.js";
8
+ import "./chunk-4WROKFN6.js";
9
9
  import {
10
10
  isReadOnlyKey,
11
11
  updateCheckEnvOptOut
12
- } from "./chunk-WLL7Q7JD.js";
12
+ } from "./chunk-SOCYTKTF.js";
13
13
 
14
14
  // src/mcp/cli.ts
15
15
  import { randomUUID } from "crypto";