@canonry/canonry 5.18.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 (34) 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-Di5c6xSa.js → AuditHistoryPanel-ddq5tdlB.js} +1 -1
  5. package/assets/assets/{BacklinksPage-CZi3sZ-7.js → BacklinksPage-g57_xzTX.js} +1 -1
  6. package/assets/assets/{HistoryPage-BY7HiZWU.js → HistoryPage-C-TdCUQ2.js} +1 -1
  7. package/assets/assets/{MeasurementPropertyPage-D3AdBHpI.js → MeasurementPropertyPage-CAADmNfw.js} +1 -1
  8. package/assets/assets/{ProjectPage-NyUl1dkF.js → ProjectPage-CoBwpHmA.js} +1 -1
  9. package/assets/assets/{RunRow-cRjiHQbt.js → RunRow-BpG0Zy-x.js} +1 -1
  10. package/assets/assets/{RunsPage-DZP_kqJs.js → RunsPage-DK3pb1LH.js} +1 -1
  11. package/assets/assets/{SettingsPage-BqJXYCDc.js → SettingsPage-BruiY8Zh.js} +1 -1
  12. package/assets/assets/{SiteHealthSection-Brr0C56X.js → SiteHealthSection-De4U11Gv.js} +3 -3
  13. package/assets/assets/{TrafficPage-k5NPSDur.js → TrafficPage-BVolLXT2.js} +1 -1
  14. package/assets/assets/{TrafficSourceDetailPage-BKNzWnxA.js → TrafficSourceDetailPage-CFDb6lPD.js} +1 -1
  15. package/assets/assets/{extract-error-message-Cnvelll0.js → extract-error-message-Bk1RTjzo.js} +1 -1
  16. package/assets/assets/index-B--AA1mG.js +86 -0
  17. package/assets/assets/{react-sigma_core.esm.min-CthGjQKl.js → react-sigma_core.esm.min--QXVK1JS.js} +1 -1
  18. package/assets/assets/{v2-overview-adapter-q2o2MzmG.js → v2-overview-adapter-CpjJPZsC.js} +1 -1
  19. package/assets/index.html +1 -1
  20. package/dist/{chunk-Y5IDGH5B.js → chunk-3IAIW5KH.js} +534 -136
  21. package/dist/chunk-4WROKFN6.js +3991 -0
  22. package/dist/{chunk-TMTO2JHU.js → chunk-EJXDABGU.js} +21 -3970
  23. package/dist/{chunk-HIFBIDOW.js → chunk-EJZFTNZG.js} +444 -185
  24. package/dist/{chunk-X3GFCKUJ.js → chunk-J3JXJIST.js} +3 -3
  25. package/dist/{chunk-HAABFHXB.js → chunk-PGOID3LE.js} +2 -2
  26. package/dist/{chunk-77VHT3JD.js → chunk-SOCYTKTF.js} +223 -23
  27. package/dist/cli.js +84 -27
  28. package/dist/{demo-server-JBGYZKAI.js → demo-server-BLDYKCFS.js} +1071 -187
  29. package/dist/index.js +6 -6
  30. package/dist/{intelligence-service-EORTVFDF.js → intelligence-service-3MHYLKMS.js} +2 -2
  31. package/dist/mcp.js +4 -4
  32. package/package.json +9 -9
  33. package/assets/assets/index-Cd_1GknE.js +0 -86
  34. package/dist/chunk-AOJU5LKX.js +0 -8
@@ -4,14 +4,14 @@ import {
4
4
  installSkills,
5
5
  loadConfigRaw,
6
6
  saveConfigPatch
7
- } from "./chunk-TMTO2JHU.js";
7
+ } from "./chunk-EJXDABGU.js";
8
8
  import {
9
9
  PACKAGE_VERSION
10
- } from "./chunk-AOJU5LKX.js";
10
+ } from "./chunk-4WROKFN6.js";
11
11
  import {
12
12
  SKILL_MANIFEST_FILENAME,
13
13
  SkillsClients
14
- } from "./chunk-77VHT3JD.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-Y5IDGH5B.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-77VHT3JD.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,
@@ -14153,6 +14318,33 @@ function agentConversationTitle(messages) {
14153
14318
  }
14154
14319
  return "New conversation";
14155
14320
  }
14321
+ var aeroPreviewStarterIds = ["status", "changes", "gaps", "insights"];
14322
+ var aeroPreviewStarterIdSchema = z46.enum(aeroPreviewStarterIds);
14323
+ var aeroPreviewStepSchema = z46.object({
14324
+ /** Assistant text shown before the tool call, when the turn narrates it. */
14325
+ text: z46.string().optional(),
14326
+ tool: z46.object({
14327
+ /** Real Canonry MCP tool name, such as canonry_visibility_report. */
14328
+ name: z46.string(),
14329
+ /** The tool's registered title, which the live bar shows as the card label. */
14330
+ label: z46.string(),
14331
+ arguments: z46.record(z46.string(), z46.unknown()),
14332
+ /** A compact excerpt of the stored result, not the full payload. */
14333
+ result: z46.unknown(),
14334
+ durationMs: z46.number().int().nonnegative()
14335
+ })
14336
+ });
14337
+ var aeroPreviewStarterSchema = z46.object({
14338
+ id: aeroPreviewStarterIdSchema,
14339
+ steps: z46.array(aeroPreviewStepSchema),
14340
+ /** Final assistant markdown. */
14341
+ answer: z46.string()
14342
+ });
14343
+ var aeroPreviewResponseSchema = z46.object({
14344
+ project: z46.string(),
14345
+ seededAt: z46.string(),
14346
+ starters: z46.array(aeroPreviewStarterSchema)
14347
+ });
14156
14348
  var agentConversationListQuerySchema = z46.object({
14157
14349
  offset: z46.coerce.number().int().min(0).default(0),
14158
14350
  limit: z46.coerce.number().int().min(1).max(100).default(50)
@@ -19450,6 +19642,7 @@ export {
19450
19642
  effectiveBrandNames,
19451
19643
  projectConfigSchema,
19452
19644
  resolveConfigSpecQueries,
19645
+ queryClassFilterSchema,
19453
19646
  compileQueryClassifier,
19454
19647
  MEASUREMENT_PLAN_V2_SCHEMA_VERSION,
19455
19648
  measurementV2UsageEdgeKey,
@@ -19523,6 +19716,10 @@ export {
19523
19716
  buildMeasurementRunManifestV1,
19524
19717
  measurementReportResponseSchema,
19525
19718
  measurementPropertyEvidenceResponseSchema,
19719
+ MEASUREMENT_PORTFOLIO_DEFAULT_LIMIT,
19720
+ MEASUREMENT_PORTFOLIO_ROW_EVIDENCE_LIMIT,
19721
+ MEASUREMENT_PORTFOLIO_ANSWER_SOURCES_LIMIT,
19722
+ MEASUREMENT_PORTFOLIO_TIE_NOTE,
19526
19723
  measurementPortfolioSummaryQuerySchema,
19527
19724
  measurementPortfolioSummaryResponseSchema,
19528
19725
  measurementPropertyQuestionsQuerySchema,
@@ -19885,9 +20082,11 @@ export {
19885
20082
  normalizeModelId,
19886
20083
  modelIdsEquivalent,
19887
20084
  brandMetricsDtoSchema,
20085
+ sourceBreakdownQuerySchema,
19888
20086
  sourceBreakdownDtoSchema,
19889
20087
  competitorLandscapeQuerySchema,
19890
20088
  COMPETITOR_LANDSCAPE_MODEL_GROUP_LIMIT,
20089
+ COMPETITOR_LANDSCAPE_OBSERVED_NAME_LIMIT,
19891
20090
  competitorLandscapeResponseSchema,
19892
20091
  parseWindow,
19893
20092
  windowCutoff,
@@ -19926,6 +20125,7 @@ export {
19926
20125
  agentConversationCreateSchema,
19927
20126
  agentConversationDeleteSchema,
19928
20127
  agentConversationTitle,
20128
+ aeroPreviewResponseSchema,
19929
20129
  agentConversationListQuerySchema,
19930
20130
  backlinkSourceSchema,
19931
20131
  BacklinkSources,
package/dist/cli.js CHANGED
@@ -35,15 +35,12 @@ import {
35
35
  trackCliCommandFinished,
36
36
  trackEvent,
37
37
  waitForServerRuntimeStartup
38
- } from "./chunk-HIFBIDOW.js";
38
+ } from "./chunk-EJZFTNZG.js";
39
39
  import {
40
40
  autoSyncSkills,
41
41
  formatAutoSyncNotice
42
- } from "./chunk-X3GFCKUJ.js";
42
+ } from "./chunk-J3JXJIST.js";
43
43
  import {
44
- CliError,
45
- EXIT_SYSTEM_ERROR,
46
- EXIT_USER_ERROR,
47
44
  configExists,
48
45
  createApiClient,
49
46
  emitInstallSummary,
@@ -52,28 +49,32 @@ import {
52
49
  getConfigPath,
53
50
  getMissingUserSkillsNudge,
54
51
  installSkills,
55
- isEndpointMissing,
56
- isMachineFormat,
57
52
  listSkills,
58
53
  loadConfig,
59
54
  loadConfigRaw,
60
- measurementDraftOperationSchema,
61
55
  parseSkillsClient,
62
- printCliError,
63
- runMeasurementDraftAction,
64
56
  saveConfig,
65
57
  saveConfigPatch,
66
- shouldPrintServeSkillsNudge,
67
- systemError,
68
- usageError
69
- } from "./chunk-TMTO2JHU.js";
58
+ shouldPrintServeSkillsNudge
59
+ } from "./chunk-EJXDABGU.js";
70
60
  import {
71
61
  DEFAULT_DEMO_TRUSTED_PROXIES,
72
62
  trustedProxiesProblem,
73
63
  trustedProxyProblem
74
64
  } from "./chunk-RB2F4D3Z.js";
75
- import "./chunk-HAABFHXB.js";
76
- import "./chunk-AOJU5LKX.js";
65
+ import "./chunk-PGOID3LE.js";
66
+ import {
67
+ CliError,
68
+ EXIT_SYSTEM_ERROR,
69
+ EXIT_USER_ERROR,
70
+ isEndpointMissing,
71
+ isMachineFormat,
72
+ measurementDraftOperationSchema,
73
+ printCliError,
74
+ runMeasurementDraftAction,
75
+ systemError,
76
+ usageError
77
+ } from "./chunk-4WROKFN6.js";
77
78
  import {
78
79
  CLOUDFLARE_WORKER_BINDINGS,
79
80
  CLOUDFLARE_WORKER_GENERATED_MARKER,
@@ -88,7 +89,7 @@ import {
88
89
  queries,
89
90
  renderReportHtml,
90
91
  runs
91
- } from "./chunk-Y5IDGH5B.js";
92
+ } from "./chunk-3IAIW5KH.js";
92
93
  import {
93
94
  AdsDeliverySnapshotStatuses,
94
95
  AdsHistoricalCampaignRollupStatuses,
@@ -164,6 +165,7 @@ import {
164
165
  normalizeProjectAliases,
165
166
  normalizeTelemetryStatus,
166
167
  notificationEventSchema,
168
+ queryClassFilterSchema,
167
169
  queryTrackingCommitRequestSchema,
168
170
  queryTrackingPreviewRequestSchema,
169
171
  reportUnattributedAnswers,
@@ -175,7 +177,7 @@ import {
175
177
  snapshotProviderModeSchema,
176
178
  visibilityReportRequestSchema,
177
179
  winnabilityClassSchema
178
- } from "./chunk-77VHT3JD.js";
180
+ } from "./chunk-SOCYTKTF.js";
179
181
 
180
182
  // src/cli.ts
181
183
  import { pathToFileURL } from "url";
@@ -440,7 +442,7 @@ function parseDemoTrustedProxies(values) {
440
442
  async function demoCommand(options) {
441
443
  const { host, port } = parseDemoListenOptions(options);
442
444
  const trustProxy = parseDemoTrustedProxies(options.trustProxy);
443
- const { createDemoServer } = await import("./demo-server-JBGYZKAI.js");
445
+ const { createDemoServer } = await import("./demo-server-BLDYKCFS.js");
444
446
  const app = await createDemoServer({ trustProxy });
445
447
  let stopping = false;
446
448
  const stop = () => {
@@ -7807,7 +7809,8 @@ function printCompetitorLandscape(data) {
7807
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.`
7808
7810
  );
7809
7811
  if (data.observedNames?.length) {
7810
- 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):");
7811
7814
  for (const row of data.observedNames) console.log(` ${row.name} \xB7 ${row.answerCount} answers`);
7812
7815
  }
7813
7816
  if (data.modelComparison) printModelComparison(data.modelComparison, data.filters.queryClass);
@@ -11434,16 +11437,46 @@ Source Origin Breakdown`);
11434
11437
  function getClient18() {
11435
11438
  return createApiClient();
11436
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
+ }
11437
11463
  var pct = (n) => `${(n * 100).toFixed(1)}%`;
11438
11464
  async function showSources(project, options) {
11439
11465
  if (options.limit !== void 0 && (!Number.isInteger(options.limit) || options.limit <= 0)) {
11440
- 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}`, {
11441
11468
  message: "--limit must be a positive integer",
11442
11469
  details: { command: "sources", option: "limit", value: options.limit }
11443
11470
  });
11444
11471
  }
11445
11472
  const client = getClient18();
11446
- 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
+ });
11447
11480
  if (options.format === "jsonl") {
11448
11481
  emitJsonl(data.ranked.entries.map((e) => ({ project, ...e })));
11449
11482
  return;
@@ -11458,6 +11491,8 @@ function printSourceRankings(data, options) {
11458
11491
  console.log(`
11459
11492
  Source Rankings (${data.window})`);
11460
11493
  console.log("\u2500".repeat(50));
11494
+ const scope = describeScope(data);
11495
+ if (scope) console.log(` ${scope}`);
11461
11496
  if (data.ranked.totalCitedSlots === 0) {
11462
11497
  console.log(" No source data available");
11463
11498
  return;
@@ -11475,8 +11510,25 @@ Source Rankings (${data.window})`);
11475
11510
  ${provider} (${list.totalCitedSlots} cited slots):`);
11476
11511
  printRankedEntries(list, " ");
11477
11512
  }
11513
+ for (const provider of data.providersWithoutSources ?? []) {
11514
+ console.log(`
11515
+ ${provider}: answered, but no answer named a source`);
11516
+ }
11478
11517
  }
11479
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
+ }
11480
11532
  function printSurfaceClasses(list) {
11481
11533
  for (const c of list.bySurfaceClass) {
11482
11534
  const noun = c.domainCount === 1 ? "domain" : "domains";
@@ -11839,25 +11891,30 @@ var OPERATOR_CLI_COMMANDS = [
11839
11891
  },
11840
11892
  {
11841
11893
  path: ["sources"],
11842
- usage: "canonry sources <project> [--rank] [--limit N] [--by-provider] [--window 7d|30d|90d|all] [--format json|jsonl]",
11894
+ usage: SOURCES_USAGE,
11843
11895
  options: {
11844
11896
  rank: { type: "boolean", default: false },
11845
11897
  "by-provider": { type: "boolean", default: false },
11846
11898
  limit: stringOption(),
11847
- window: stringOption()
11899
+ window: stringOption(),
11900
+ "query-class": stringOption(),
11901
+ "run-id": stringOption(),
11902
+ "include-by-query": stringOption()
11848
11903
  },
11849
11904
  run: async (input) => {
11850
- const usage = "canonry sources <project> [--rank] [--limit N] [--by-provider] [--window 7d|30d|90d|all] [--format json|jsonl]";
11851
- const project = requireProject(input, "sources", usage);
11905
+ const project = requireProject(input, "sources", SOURCES_USAGE);
11852
11906
  await showSources(project, {
11853
11907
  rank: getBoolean(input.values, "rank"),
11854
11908
  byProvider: getBoolean(input.values, "by-provider"),
11855
11909
  limit: parseIntegerOption(input, "limit", {
11856
11910
  message: "--limit must be an integer",
11857
- usage,
11911
+ usage: SOURCES_USAGE,
11858
11912
  command: "sources"
11859
11913
  }),
11860
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")),
11861
11918
  format: input.format
11862
11919
  });
11863
11920
  }