@ainyc/canonry 4.180.8 → 4.182.3

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 (36) hide show
  1. package/README.md +77 -46
  2. package/assets/assets/{AuditHistoryPanel-qiuqNGvG.js → AuditHistoryPanel-1_FHpzj-.js} +1 -1
  3. package/assets/assets/{BacklinksPage-D-g5f0Xv.js → BacklinksPage-045za10_.js} +1 -1
  4. package/assets/assets/{ChartPrimitives-DG35TyhH.js → ChartPrimitives-DLEICrrL.js} +1 -1
  5. package/assets/assets/{HistoryPage-q8_pCuOs.js → HistoryPage-36K_6asu.js} +1 -1
  6. package/assets/assets/{MeasurementPropertyPage-C_wMjUZe.js → MeasurementPropertyPage-B4DJGoY6.js} +1 -1
  7. package/assets/assets/ProjectPage-CshC68Ne.js +9 -0
  8. package/assets/assets/{RunRow-D5hatdlY.js → RunRow-U2CN755e.js} +1 -1
  9. package/assets/assets/{RunsPage-Bj2snMM3.js → RunsPage-D0CtU4d-.js} +1 -1
  10. package/assets/assets/{SettingsPage-Cf5YgyJv.js → SettingsPage-zMWieTPK.js} +1 -1
  11. package/assets/assets/{SiteHealthSection-D8RLvMAE.js → SiteHealthSection-TpQPu_Uj.js} +3 -3
  12. package/assets/assets/{TrafficPage-CotJ14le.js → TrafficPage-DfLUt-64.js} +1 -1
  13. package/assets/assets/{TrafficSourceDetailPage-BcxYX-uq.js → TrafficSourceDetailPage-DbjNNWSt.js} +1 -1
  14. package/assets/assets/extract-error-message-CWqz1QPC.js +1 -0
  15. package/assets/assets/index-Brb7M_6G.js +86 -0
  16. package/assets/assets/{index-DXCQf5s1.css → index-DwdK2e4e.css} +1 -1
  17. package/assets/assets/{react-sigma_core.esm.min-DxZINEmi.js → react-sigma_core.esm.min-Drqprr9L.js} +1 -1
  18. package/assets/assets/{vendor-lucide-nYKv-BB7.js → vendor-lucide-XjCNFK0x.js} +1 -1
  19. package/assets/assets/{vendor-markdown-Bn7fRwrx.js → vendor-markdown-9tTeP8v7.js} +1 -1
  20. package/assets/assets/{vendor-radix-4UOaVWza.js → vendor-radix-BpmvLvpp.js} +1 -1
  21. package/assets/assets/{vendor-recharts-D8rt5lKn.js → vendor-recharts-FA0uySU7.js} +1 -1
  22. package/assets/assets/{vendor-tanstack-Dock0eH1.js → vendor-tanstack-CYBjbqVr.js} +1 -1
  23. package/assets/index.html +7 -7
  24. package/dist/{chunk-GFVZOVG3.js → chunk-BDJT7XZL.js} +68 -4
  25. package/dist/{chunk-GN2G7VFK.js → chunk-DY5ZDKQW.js} +159 -0
  26. package/dist/{chunk-IM4HFNGF.js → chunk-FVC7PGYQ.js} +41 -1
  27. package/dist/{chunk-G7M2KM7Q.js → chunk-I3KSOMJA.js} +2 -2
  28. package/dist/{chunk-ZJ2VGTYU.js → chunk-K45YKXE4.js} +4272 -3387
  29. package/dist/cli.js +141 -8
  30. package/dist/index.js +4 -4
  31. package/dist/{intelligence-service-IURLYRB3.js → intelligence-service-HGA553GT.js} +2 -2
  32. package/dist/mcp.js +3 -3
  33. package/package.json +10 -10
  34. package/assets/assets/ProjectPage-33THfDtC.js +0 -9
  35. package/assets/assets/extract-error-message-Bxt42scd.js +0 -1
  36. package/assets/assets/index-BlILyZJ5.js +0 -86
package/assets/index.html CHANGED
@@ -12,14 +12,14 @@
12
12
  <link rel="icon" type="image/png" sizes="32x32" href="./favicon-32.png" />
13
13
  <link rel="apple-touch-icon" href="./apple-touch-icon.png" />
14
14
  <title>Canonry</title>
15
- <script type="module" crossorigin src="./assets/index-BlILyZJ5.js"></script>
16
- <link rel="modulepreload" crossorigin href="./assets/vendor-tanstack-Dock0eH1.js">
17
- <link rel="modulepreload" crossorigin href="./assets/vendor-radix-4UOaVWza.js">
18
- <link rel="modulepreload" crossorigin href="./assets/vendor-recharts-D8rt5lKn.js">
19
- <link rel="modulepreload" crossorigin href="./assets/vendor-lucide-nYKv-BB7.js">
20
- <link rel="modulepreload" crossorigin href="./assets/vendor-markdown-Bn7fRwrx.js">
15
+ <script type="module" crossorigin src="./assets/index-Brb7M_6G.js"></script>
16
+ <link rel="modulepreload" crossorigin href="./assets/vendor-tanstack-CYBjbqVr.js">
17
+ <link rel="modulepreload" crossorigin href="./assets/vendor-radix-BpmvLvpp.js">
18
+ <link rel="modulepreload" crossorigin href="./assets/vendor-recharts-FA0uySU7.js">
19
+ <link rel="modulepreload" crossorigin href="./assets/vendor-lucide-XjCNFK0x.js">
20
+ <link rel="modulepreload" crossorigin href="./assets/vendor-markdown-9tTeP8v7.js">
21
21
  <link rel="modulepreload" crossorigin href="./assets/vendor-yaml-GWJz5H2G.js">
22
- <link rel="stylesheet" crossorigin href="./assets/index-DXCQf5s1.css">
22
+ <link rel="stylesheet" crossorigin href="./assets/index-DwdK2e4e.css">
23
23
  </head>
24
24
  <body>
25
25
  <div id="root"></div>
@@ -11,7 +11,7 @@ import {
11
11
  loadConfig,
12
12
  loadConfigRaw,
13
13
  saveConfigPatch
14
- } from "./chunk-IM4HFNGF.js";
14
+ } from "./chunk-FVC7PGYQ.js";
15
15
  import {
16
16
  CC_CACHE_DIR,
17
17
  DUCKDB_SPEC,
@@ -157,7 +157,7 @@ import {
157
157
  siteCrawlSnapshots,
158
158
  toAlertView,
159
159
  usageCounters
160
- } from "./chunk-ZJ2VGTYU.js";
160
+ } from "./chunk-K45YKXE4.js";
161
161
  import {
162
162
  AGENT_MEMORY_VALUE_MAX_BYTES,
163
163
  AGENT_PROVIDER_IDS,
@@ -296,7 +296,7 @@ import {
296
296
  validationError,
297
297
  winnabilityClassLabel,
298
298
  withRetry
299
- } from "./chunk-GN2G7VFK.js";
299
+ } from "./chunk-DY5ZDKQW.js";
300
300
 
301
301
  // src/telemetry.ts
302
302
  import crypto from "crypto";
@@ -11867,7 +11867,7 @@ function readStoredGroundingSources(rawResponse) {
11867
11867
  return result;
11868
11868
  }
11869
11869
  async function backfillInsightsCommand(project, opts) {
11870
- const { IntelligenceService: IntelligenceService2 } = await import("./intelligence-service-IURLYRB3.js");
11870
+ const { IntelligenceService: IntelligenceService2 } = await import("./intelligence-service-HGA553GT.js");
11871
11871
  const config = loadConfig();
11872
11872
  const db = createClient(config.database);
11873
11873
  migrate(db);
@@ -13803,6 +13803,68 @@ function trimRowsToFit(rows, render) {
13803
13803
  }
13804
13804
  return kept;
13805
13805
  }
13806
+ function nestedArrayCandidates(root) {
13807
+ const candidates = [];
13808
+ const visit = (object) => {
13809
+ let containsRecordCollection = false;
13810
+ for (const [key, value] of Object.entries(object)) {
13811
+ if (Array.isArray(value)) {
13812
+ let hasNestedRecords = false;
13813
+ let hasRecordRows = false;
13814
+ for (const row of value) {
13815
+ if (row && typeof row === "object" && !Array.isArray(row)) {
13816
+ hasRecordRows = true;
13817
+ hasNestedRecords = visit(row) || hasNestedRecords;
13818
+ }
13819
+ }
13820
+ if (value.length > 0 && !hasNestedRecords) {
13821
+ candidates.push({ owner: object, key, rows: value, size: serializeResult(value).length, hasRecordRows });
13822
+ }
13823
+ containsRecordCollection = hasRecordRows || hasNestedRecords || containsRecordCollection;
13824
+ } else if (value && typeof value === "object") {
13825
+ containsRecordCollection = visit(value) || containsRecordCollection;
13826
+ }
13827
+ }
13828
+ return containsRecordCollection;
13829
+ };
13830
+ visit(root);
13831
+ return candidates.sort(
13832
+ (left, right) => Number(right.hasRecordRows) - Number(left.hasRecordRows) || right.size - left.size
13833
+ );
13834
+ }
13835
+ function trimNestedArrays(full) {
13836
+ const parsed = JSON.parse(full);
13837
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return void 0;
13838
+ const copy = parsed;
13839
+ copy.__truncated = true;
13840
+ let out = serializeResult(copy);
13841
+ while (out.length > MAX_TOOL_RESULT_CHARS) {
13842
+ const candidate = nestedArrayCandidates(copy).at(0);
13843
+ if (!candidate) return void 0;
13844
+ const { owner, key, rows } = candidate;
13845
+ const previous = owner.__omittedRowsByField;
13846
+ const omitted = previous && typeof previous === "object" && !Array.isArray(previous) ? { ...previous } : {};
13847
+ const priorCount = typeof omitted[key] === "number" ? omitted[key] : 0;
13848
+ owner.__truncated = true;
13849
+ owner.__omittedRowsByField = omitted;
13850
+ const keep = (count2) => {
13851
+ owner[key] = rows.slice(0, count2);
13852
+ omitted[key] = priorCount + rows.length - count2;
13853
+ return serializeResult(copy);
13854
+ };
13855
+ out = keep(0);
13856
+ if (out.length > MAX_TOOL_RESULT_CHARS) continue;
13857
+ let low = 0;
13858
+ let high = rows.length - 1;
13859
+ while (low < high) {
13860
+ const middle = Math.ceil((low + high) / 2);
13861
+ if (keep(middle).length <= MAX_TOOL_RESULT_CHARS) low = middle;
13862
+ else high = middle - 1;
13863
+ }
13864
+ out = keep(low);
13865
+ }
13866
+ return out;
13867
+ }
13806
13868
  function truncateToolResult(details) {
13807
13869
  const full = serializeResult(details);
13808
13870
  if (full.length <= MAX_TOOL_RESULT_CHARS) return full;
@@ -13830,6 +13892,8 @@ function truncateToolResult(details) {
13830
13892
  });
13831
13893
  if (out.length <= MAX_TOOL_RESULT_CHARS) return out;
13832
13894
  }
13895
+ const nested = trimNestedArrays(full);
13896
+ if (nested !== void 0) return nested;
13833
13897
  }
13834
13898
  return full.slice(0, MAX_TOOL_RESULT_CHARS) + "\n" + TRUNCATION_NOTE;
13835
13899
  }
@@ -6723,6 +6723,22 @@ var measurementDraftUpsertCompetitorRequestSchema = z15.object({
6723
6723
  groupKey: measurementV2StableKeySchema,
6724
6724
  competitor: measurementDraftCompetitorSchema
6725
6725
  }).strict();
6726
+ var measurementDraftPinCompetitorRequestSchema = z15.object({
6727
+ expectedActiveRevision: measurementDraftRevisionSchema,
6728
+ groupKey: measurementV2StableKeySchema,
6729
+ domain: z15.string().trim().min(1).refine((value) => hostOf(value) !== null, "A competitor domain must be a valid hostname"),
6730
+ label: z15.string().trim().min(1).optional(),
6731
+ aliases: z15.array(z15.string().trim().min(1)).optional()
6732
+ }).strict();
6733
+ var measurementDraftPinCompetitorResponseSchema = measurementDraftMutationResponseSchema.extend({
6734
+ groupKey: measurementV2StableKeySchema,
6735
+ competitor: measurementDraftCompetitorSchema,
6736
+ draftCreated: z15.boolean(),
6737
+ published: z15.object({
6738
+ revision: measurementDraftRevisionSchema,
6739
+ competitorsChanged: z15.literal(false)
6740
+ }).strict()
6741
+ }).strict();
6726
6742
  var measurementDraftRemoveCompetitorRequestSchema = z15.object({
6727
6743
  groupKey: measurementV2StableKeySchema,
6728
6744
  competitorKey: measurementV2StableKeySchema
@@ -11835,6 +11851,143 @@ var sourceBreakdownDtoSchema = z35.object({
11835
11851
  /** Applied ranked-list limit; null when the full list is returned. */
11836
11852
  limit: z35.number().int().nullable()
11837
11853
  });
11854
+ var competitorLandscapeSurfaceClassSchema = z35.enum([
11855
+ "own",
11856
+ "direct-competitor",
11857
+ "ota-aggregator",
11858
+ "editorial-media",
11859
+ "other",
11860
+ "unknown"
11861
+ ]);
11862
+ var competitorLandscapeScopeSchema = z35.discriminatedUnion("kind", [
11863
+ z35.object({ kind: z35.literal("project") }).strict(),
11864
+ z35.object({ kind: z35.literal("group"), groupKey: z35.string().trim().min(1) }).strict(),
11865
+ z35.object({ kind: z35.literal("all-markets") }).strict()
11866
+ ]);
11867
+ var competitorLandscapeQueryClassSchema = z35.enum(["all", "branded", "non-brand"]);
11868
+ var competitorLandscapeModeSchema = z35.enum(["project", "all-markets"]);
11869
+ var competitorLandscapeQuerySchema = z35.object({
11870
+ window: metricsWindowSchema.optional(),
11871
+ groupKey: z35.string().trim().min(1).optional(),
11872
+ scope: competitorLandscapeModeSchema.optional(),
11873
+ provider: z35.string().trim().min(1).optional(),
11874
+ /** Exact requested model ID; provider is required to disambiguate model names. */
11875
+ model: modelIdSchema.optional(),
11876
+ /** Opt-in agent comparison; the default landscape remains pooled. */
11877
+ groupBy: z35.literal("model").optional(),
11878
+ queryClass: competitorLandscapeQueryClassSchema.optional(),
11879
+ location: z35.string().trim().min(1).optional(),
11880
+ runId: z35.string().trim().min(1).optional()
11881
+ }).strict().superRefine((value, context) => {
11882
+ if (value.scope === "all-markets" && value.groupKey !== void 0) {
11883
+ context.addIssue({
11884
+ code: "custom",
11885
+ path: ["groupKey"],
11886
+ message: "groupKey cannot be combined with scope=all-markets"
11887
+ });
11888
+ }
11889
+ if (value.model !== void 0 && value.provider === void 0) {
11890
+ context.addIssue({
11891
+ code: "custom",
11892
+ path: ["provider"],
11893
+ message: "provider is required when filtering by model"
11894
+ });
11895
+ }
11896
+ });
11897
+ var competitorLandscapeRowSchema = z35.object({
11898
+ domain: z35.string().trim().min(1),
11899
+ label: z35.string().trim().min(1),
11900
+ surfaceClass: competitorLandscapeSurfaceClassSchema,
11901
+ pinned: z35.boolean(),
11902
+ /** One answer-text match at most per result. */
11903
+ mentionCount: z35.number().int().nonnegative(),
11904
+ /**
11905
+ * Percentage points (0..100). Null outside the competitive denominator, and
11906
+ * null for any selection that pools query classes: a brand wins its own
11907
+ * branded queries by definition, so a pooled ratio flatters the project and
11908
+ * buries every competitor. Counts stay populated either way.
11909
+ */
11910
+ shareOfVoice: z35.number().min(0).max(100).nullable(),
11911
+ /** One source-list credit at most per result. Independent of mentions. */
11912
+ citationCount: z35.number().int().nonnegative(),
11913
+ /** Answer-text result count behind the mention field. */
11914
+ answeredResults: z35.number().int().nonnegative(),
11915
+ firstSeenAt: z35.string().datetime().nullable(),
11916
+ lastSeenAt: z35.string().datetime().nullable(),
11917
+ sampleUrls: z35.array(z35.string().url()).max(3)
11918
+ }).strict();
11919
+ var competitorLandscapeEvidenceSchema = z35.object({
11920
+ answeredResults: z35.number().int().nonnegative(),
11921
+ sourceResults: z35.number().int().nonnegative(),
11922
+ missingAnswerTextResults: z35.number().int().nonnegative(),
11923
+ /** Project plus direct-competitor named credits behind SOV. */
11924
+ mentionCredits: z35.number().int().nonnegative(),
11925
+ /** Citation captures that cannot prove a complete source list; never inferred as misses. */
11926
+ incompleteSourceResults: z35.number().int().nonnegative(),
11927
+ /** Stored probe snapshots intentionally omitted from every landscape metric. */
11928
+ excludedProbeResults: z35.number().int().nonnegative(),
11929
+ /** Stored snapshots from queued/running/failed/cancelled runs omitted from every metric. */
11930
+ excludedNonCompletedResults: z35.number().int().nonnegative()
11931
+ }).strict();
11932
+ var COMPETITOR_LANDSCAPE_MODEL_GROUP_LIMIT = 50;
11933
+ var competitorLandscapeModelGroupSchema = z35.object({
11934
+ provider: z35.string().trim().min(1),
11935
+ /** Null preserves historical observations with unknown requested model identity. */
11936
+ model: modelIdSchema.nullable(),
11937
+ /** Raw upstream-reported identity; never filled from the requested model or current settings. */
11938
+ servedModels: modelEvidenceStateSchema,
11939
+ snapshotCount: z35.number().int().positive(),
11940
+ project: competitorLandscapeRowSchema,
11941
+ pinned: z35.array(competitorLandscapeRowSchema),
11942
+ observed: z35.array(competitorLandscapeRowSchema),
11943
+ otherSources: z35.array(competitorLandscapeRowSchema),
11944
+ evidence: competitorLandscapeEvidenceSchema,
11945
+ /** Per-group ranked-row truncation; all pins and full-population denominators remain included. */
11946
+ truncated: z35.boolean()
11947
+ }).strict();
11948
+ var competitorLandscapeModelComparisonSchema = z35.object({
11949
+ basis: z35.literal("requested-model"),
11950
+ groups: z35.array(competitorLandscapeModelGroupSchema).max(COMPETITOR_LANDSCAPE_MODEL_GROUP_LIMIT),
11951
+ totalGroups: z35.number().int().nonnegative(),
11952
+ /** Groups sort by provider and requested model. Use provider/model filters to narrow a truncated result. */
11953
+ truncated: z35.boolean()
11954
+ }).strict();
11955
+ var competitorLandscapeResponseSchema = z35.object({
11956
+ window: metricsWindowSchema,
11957
+ scope: competitorLandscapeScopeSchema,
11958
+ project: competitorLandscapeRowSchema,
11959
+ /** Explicit/custom competitors, preserved even with zero observations. */
11960
+ pinned: z35.array(competitorLandscapeRowSchema),
11961
+ /** Stored-discovery direct competitors, ordered by historical mention share. */
11962
+ observed: z35.array(competitorLandscapeRowSchema),
11963
+ /** Aggregators, editorial, unknown, and other cited sources; never share-of-voice competitors. */
11964
+ otherSources: z35.array(competitorLandscapeRowSchema),
11965
+ evidence: competitorLandscapeEvidenceSchema,
11966
+ /** Present only when groupBy=model; pooled fields remain available and unchanged. */
11967
+ modelComparison: competitorLandscapeModelComparisonSchema.optional(),
11968
+ /** Present only for Advanced market reads; active metrics stay frozen while draft pins remain pending publish. */
11969
+ marketState: z35.object({
11970
+ activeRevision: z35.number().int().positive(),
11971
+ draft: z35.object({
11972
+ etag: z35.string().trim().min(1),
11973
+ /** Draft-only market identities included in `pinned` for this response. */
11974
+ pendingCompetitorDomains: z35.array(z35.string().trim().min(1))
11975
+ }).strict().nullable()
11976
+ }).strict().nullable(),
11977
+ /** Echoes all applied filters so a client never mistakes a scoped reading for a project-wide one. */
11978
+ filters: z35.object({
11979
+ scope: competitorLandscapeModeSchema,
11980
+ groupKey: z35.string().nullable(),
11981
+ provider: z35.string().nullable(),
11982
+ model: modelIdSchema.optional(),
11983
+ groupBy: z35.literal("model").optional(),
11984
+ queryClass: competitorLandscapeQueryClassSchema,
11985
+ location: z35.string().nullable(),
11986
+ runId: z35.string().nullable()
11987
+ }).strict(),
11988
+ /** True when ranked observed/source lists exceed the server cap; pinned rows are never dropped. */
11989
+ truncated: z35.boolean()
11990
+ }).strict();
11838
11991
  function parseWindow(value) {
11839
11992
  if (value === void 0 || value === "") return "all";
11840
11993
  const parsed = metricsWindowSchema.safeParse(value);
@@ -16589,6 +16742,7 @@ export {
16589
16742
  measurementChangesResponseSchema,
16590
16743
  measurementDataQualityQuerySchema,
16591
16744
  measurementDataQualityResponseSchema,
16745
+ measurementDraftCompetitorSchema,
16592
16746
  measurementDraftAuthoringSchema,
16593
16747
  MEASUREMENT_DRAFT_MAX_ASSIGNMENTS_PER_ACTION,
16594
16748
  MEASUREMENT_DRAFT_MAX_GROUPS,
@@ -16621,6 +16775,8 @@ export {
16621
16775
  measurementDraftUpsertGroupRequestSchema,
16622
16776
  measurementDraftRemoveGroupRequestSchema,
16623
16777
  measurementDraftUpsertCompetitorRequestSchema,
16778
+ measurementDraftPinCompetitorRequestSchema,
16779
+ measurementDraftPinCompetitorResponseSchema,
16624
16780
  measurementDraftRemoveCompetitorRequestSchema,
16625
16781
  measurementDraftCompilePreviewResponseSchema,
16626
16782
  measurementDraftDiffPreviewResponseSchema,
@@ -16920,6 +17076,9 @@ export {
16920
17076
  modelIdsEquivalent,
16921
17077
  brandMetricsDtoSchema,
16922
17078
  sourceBreakdownDtoSchema,
17079
+ competitorLandscapeQuerySchema,
17080
+ COMPETITOR_LANDSCAPE_MODEL_GROUP_LIMIT,
17081
+ competitorLandscapeResponseSchema,
16923
17082
  parseWindow,
16924
17083
  windowCutoff,
16925
17084
  resolveDateRange,
@@ -25,6 +25,7 @@ import {
25
25
  classifySkillFile,
26
26
  coerceSkillManifest,
27
27
  competitorBatchRequestSchema,
28
+ competitorLandscapeQuerySchema,
28
29
  describeError,
29
30
  discoveryBucketSchema,
30
31
  discoveryCompetitorTypeSchema,
@@ -92,7 +93,7 @@ import {
92
93
  trafficConnectWordpressRequestSchema,
93
94
  trafficEventKindSchema,
94
95
  trafficSeriesGranularitySchema
95
- } from "./chunk-GN2G7VFK.js";
96
+ } from "./chunk-DY5ZDKQW.js";
96
97
 
97
98
  // src/config.ts
98
99
  import fs from "fs";
@@ -2398,6 +2399,18 @@ var postApiV1ProjectsByNameCompetitors = (options) => {
2398
2399
  }
2399
2400
  });
2400
2401
  };
2402
+ var getApiV1ProjectsByNameAnalyticsCompetitors = (options) => {
2403
+ return (options.client ?? client).get({
2404
+ security: [
2405
+ {
2406
+ scheme: "bearer",
2407
+ type: "http"
2408
+ }
2409
+ ],
2410
+ url: "/api/v1/projects/{name}/analytics/competitors",
2411
+ ...options
2412
+ });
2413
+ };
2401
2414
  var getApiV1ProjectsByNameRuns = (options) => {
2402
2415
  return (options.client ?? client).get({
2403
2416
  security: [
@@ -6583,6 +6596,16 @@ var ApiClient = class {
6583
6596
  })
6584
6597
  );
6585
6598
  }
6599
+ /** Stored competitor SOV, optionally grouped or filtered by requested model; never starts provider work. */
6600
+ async getCompetitorLandscape(project, opts = {}) {
6601
+ return this.invoke(
6602
+ () => getApiV1ProjectsByNameAnalyticsCompetitors({
6603
+ client: this.heyClient,
6604
+ path: { name: project },
6605
+ query: opts
6606
+ })
6607
+ );
6608
+ }
6586
6609
  async getAnalyticsGaps(project, window) {
6587
6610
  return this.invoke(
6588
6611
  () => getApiV1ProjectsByNameAnalyticsGaps({
@@ -9088,6 +9111,9 @@ var competitorsInputSchema = z3.object({
9088
9111
  project: projectNameSchema,
9089
9112
  request: competitorBatchRequestSchema
9090
9113
  });
9114
+ var competitorLandscapeInputSchema = competitorLandscapeQuerySchema.safeExtend({
9115
+ project: projectNameSchema
9116
+ }).strict();
9091
9117
  var projectUpsertInputSchema = z3.object({
9092
9118
  project: projectNameSchema,
9093
9119
  request: projectUpsertRequestSchema
@@ -9480,6 +9506,20 @@ var canonryMcpTools = [
9480
9506
  openApiOperations: ["GET /api/v1/projects/{name}/analytics/sources"],
9481
9507
  handler: (client2, input) => client2.getAnalyticsSources(input.project, { window: input.window, limit: input.limit })
9482
9508
  }),
9509
+ defineTool({
9510
+ name: "canonry_competitor_landscape",
9511
+ title: "Get historical competitor landscape",
9512
+ description: "Returns pinned competitors first, then observed direct competitors and other cited sources from stored answer/source evidence only. Mention share is percentage points (0..100) from answer text; citations are independent. Share of voice needs ONE query class: `queryClass=all`, and omitting it, pool branded and non-brand, so every `shareOfVoice` comes back null and only the counts are published. Pass `queryClass=non-brand` (or `branded`) for a ratio, exactly as visibility-stats does. A project with no brand name or alias cannot be split by class, so a class-scoped read on one is refused rather than answered empty. Optional groupBy: model adds provider/requested-model groups with separate served-model evidence and sample counts. Optional model filters one exact requested model ID and requires provider. Unknown historical models remain explicit. Groups are not a matched-query or equal-weight comparison. Advanced reads support one market group or explicit scope: all-markets. No provider, discovery, or classifier work runs. Ranked lists are capped at 100 observed/other-source rows per group; pins remain complete. Model groups are capped at 50 and disclose truncation.",
9513
+ access: "read",
9514
+ tier: "monitoring",
9515
+ inputSchema: competitorLandscapeInputSchema,
9516
+ annotations: readAnnotations(),
9517
+ openApiOperations: ["GET /api/v1/projects/{name}/analytics/competitors"],
9518
+ handler: (client2, input) => {
9519
+ const { project, ...query } = input;
9520
+ return client2.getCompetitorLandscape(project, query);
9521
+ }
9522
+ }),
9483
9523
  defineTool({
9484
9524
  name: "canonry_search",
9485
9525
  title: "Search project (composite)",
@@ -5,11 +5,11 @@ import {
5
5
  installSkills,
6
6
  loadConfigRaw,
7
7
  saveConfigPatch
8
- } from "./chunk-IM4HFNGF.js";
8
+ } from "./chunk-FVC7PGYQ.js";
9
9
  import {
10
10
  SKILL_MANIFEST_FILENAME,
11
11
  SkillsClients
12
- } from "./chunk-GN2G7VFK.js";
12
+ } from "./chunk-DY5ZDKQW.js";
13
13
 
14
14
  // src/skills-autosync.ts
15
15
  import fs from "fs";