@canonry/canonry 4.146.0 → 4.147.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 (31) hide show
  1. package/assets/assets/{AuditHistoryPanel-IDsSUFI3.js → AuditHistoryPanel-BbEZ_0W9.js} +1 -1
  2. package/assets/assets/{BacklinksPage-BswN-pyj.js → BacklinksPage-B72RKxC-.js} +1 -1
  3. package/assets/assets/{ChartPrimitives-CIe-R58_.js → ChartPrimitives-Cf-jQ3c8.js} +1 -1
  4. package/assets/assets/{HistoryPage-B18Jpq8c.js → HistoryPage-C2U1kxKw.js} +1 -1
  5. package/assets/assets/MeasurementPropertyPage-ltcSZ0tw.js +1 -0
  6. package/assets/assets/ProjectPage-ZcGjsDlb.js +12 -0
  7. package/assets/assets/{RunRow-3ZwTR4Bv.js → RunRow-DxO-zxCm.js} +1 -1
  8. package/assets/assets/{RunsPage-BCAJulR1.js → RunsPage-B1ON2nQC.js} +1 -1
  9. package/assets/assets/{SettingsPage-BT2_l0Do.js → SettingsPage-Cp0bHFHk.js} +1 -1
  10. package/assets/assets/{TrafficPage-Cux8rj5G.js → TrafficPage-QzitDjhV.js} +1 -1
  11. package/assets/assets/{TrafficSourceDetailPage-DI1Ad8KS.js → TrafficSourceDetailPage-BjfFyG2y.js} +1 -1
  12. package/assets/assets/{arrow-left-BMSx9HQB.js → arrow-left-DJ8ZwUlj.js} +1 -1
  13. package/assets/assets/extract-error-message-CX8ZNJ8S.js +1 -0
  14. package/assets/assets/{index-C6E5hp28.css → index-D5NO3NEG.css} +1 -1
  15. package/assets/assets/index-DF8X6nM0.js +213 -0
  16. package/assets/assets/{trash-2-CyoJtRAr.js → trash-2-UHAxuTT7.js} +1 -1
  17. package/assets/assets/{v2-overview-adapter-owDeFdUc.js → v2-overview-adapter-BHmxTmCf.js} +1 -1
  18. package/assets/index.html +2 -2
  19. package/dist/{chunk-UQOTEIA6.js → chunk-2NTWZHNF.js} +712 -330
  20. package/dist/{chunk-B5H55ZMA.js → chunk-BVOU4UJM.js} +3687 -3025
  21. package/dist/{chunk-Z7B6BRPP.js → chunk-GNKVF6TZ.js} +7 -4
  22. package/dist/{chunk-ED7C5TWT.js → chunk-ZRUNFIGA.js} +3818 -1439
  23. package/dist/cli.js +419 -15
  24. package/dist/index.js +4 -4
  25. package/dist/{intelligence-service-M5UNHF7X.js → intelligence-service-2E5YAXI3.js} +2 -2
  26. package/dist/mcp.js +5 -5
  27. package/package.json +12 -11
  28. package/assets/assets/MeasurementPropertyPage-CvmQeoo7.js +0 -1
  29. package/assets/assets/ProjectPage-BE1MUAB5.js +0 -11
  30. package/assets/assets/extract-error-message-B-9FdQh8.js +0 -1
  31. package/assets/assets/index-kOXUzdqD.js +0 -213
package/dist/cli.js CHANGED
@@ -30,7 +30,7 @@ import {
30
30
  showFirstRunNotice,
31
31
  trackCliCommandFinished,
32
32
  trackEvent
33
- } from "./chunk-Z7B6BRPP.js";
33
+ } from "./chunk-GNKVF6TZ.js";
34
34
  import {
35
35
  CliError,
36
36
  EXIT_SYSTEM_ERROR,
@@ -43,11 +43,14 @@ import {
43
43
  isMachineFormat,
44
44
  loadConfig,
45
45
  loadConfigRaw,
46
+ measurementDraftOperationSchema,
46
47
  printCliError,
48
+ runMeasurementDraftAction,
47
49
  saveConfig,
48
50
  saveConfigPatch,
51
+ systemError,
49
52
  usageError
50
- } from "./chunk-UQOTEIA6.js";
53
+ } from "./chunk-2NTWZHNF.js";
51
54
  import {
52
55
  apiKeys,
53
56
  createClient,
@@ -55,7 +58,7 @@ import {
55
58
  projects,
56
59
  queries,
57
60
  renderReportHtml
58
- } from "./chunk-ED7C5TWT.js";
61
+ } from "./chunk-ZRUNFIGA.js";
59
62
  import {
60
63
  AdsDeliverySnapshotStatuses,
61
64
  AdsHistoricalCampaignRollupStatuses,
@@ -68,6 +71,7 @@ import {
68
71
  CheckScopes,
69
72
  CheckStatuses,
70
73
  CitationStates,
74
+ MeasurementEvidenceShapes,
71
75
  READ_ONLY_SCOPE,
72
76
  REPORT_PERIOD_OPTIONS,
73
77
  ResearchRunStatuses,
@@ -98,15 +102,27 @@ import {
98
102
  formatMicros,
99
103
  formatRatio,
100
104
  formatRunErrorOneLine,
105
+ measurementChangesQuerySchema,
106
+ measurementDataQualityQuerySchema,
101
107
  measurementDiscoveryRequestSchema,
102
108
  measurementDiscoveryRuleSchema,
109
+ measurementDraftCollectionQuerySchema,
110
+ measurementOverviewQuerySchema,
111
+ measurementPlanDeactivateRequestSchema,
103
112
  measurementPlanInputSchema,
113
+ measurementPortfolioSummaryQuerySchema,
114
+ measurementPropertyCompetitorsQuerySchema,
115
+ measurementPropertyQuestionsQuerySchema,
116
+ measurementQuerySetUpsertRequestSchema,
117
+ measurementQueryTemplateApplyRequestSchema,
118
+ measurementQueryTemplateUpsertRequestSchema,
119
+ measurementQuestionResultQuerySchema,
104
120
  normalizeProjectAliases,
105
121
  notificationEventSchema,
106
122
  providerQuotaPolicySchema,
107
123
  resolveProviderInput,
108
124
  winnabilityClassSchema
109
- } from "./chunk-B5H55ZMA.js";
125
+ } from "./chunk-BVOU4UJM.js";
110
126
 
111
127
  // src/cli.ts
112
128
  import { pathToFileURL } from "url";
@@ -15714,8 +15730,10 @@ Usage: ${usage}`, {
15714
15730
  ];
15715
15731
 
15716
15732
  // src/commands/measurement-plan.ts
15733
+ import crypto3 from "crypto";
15717
15734
  import fs16 from "fs";
15718
15735
  import { parse } from "yaml";
15736
+ import { z as z2 } from "zod";
15719
15737
  function readPlan(source) {
15720
15738
  const content = source === "-" ? fs16.readFileSync(0, "utf8") : fs16.readFileSync(source, "utf8");
15721
15739
  const parsed = source.endsWith(".json") ? JSON.parse(content) : parse(content);
@@ -15726,6 +15744,171 @@ function readDiscoveryRule(source) {
15726
15744
  const parsed = source.endsWith(".json") ? JSON.parse(content) : parse(content);
15727
15745
  return measurementDiscoveryRuleSchema.parse(parsed);
15728
15746
  }
15747
+ var ADVANCED_MEASUREMENT_OPERATIONS = [
15748
+ "setup",
15749
+ "overview",
15750
+ "portfolio-summary",
15751
+ "property-questions",
15752
+ "question-result",
15753
+ "property-competitors",
15754
+ "changes",
15755
+ "data-quality",
15756
+ "draft",
15757
+ "draft-targets",
15758
+ "draft-assignments",
15759
+ "draft-groups",
15760
+ "draft-action",
15761
+ "deactivate",
15762
+ "query-sets",
15763
+ "query-set-get",
15764
+ "query-set-upsert",
15765
+ "query-set-delete",
15766
+ "query-templates",
15767
+ "query-template-upsert",
15768
+ "query-template-delete",
15769
+ "query-template-apply"
15770
+ ];
15771
+ var advancedIdempotencyKeySchema = z2.string().trim().min(1);
15772
+ var advancedResourceIdSchema = z2.string().trim().min(1);
15773
+ var advancedEmptyInputSchema = z2.object({}).strict();
15774
+ var advancedQuerySetInputSchema = z2.object({ setId: advancedResourceIdSchema }).strict();
15775
+ var advancedQuerySetUpsertInputSchema = advancedQuerySetInputSchema.extend({
15776
+ request: measurementQuerySetUpsertRequestSchema
15777
+ }).strict();
15778
+ var advancedQueryTemplateInputSchema = z2.object({ templateId: advancedResourceIdSchema }).strict();
15779
+ var advancedQueryTemplateUpsertInputSchema = advancedQueryTemplateInputSchema.extend({
15780
+ request: measurementQueryTemplateUpsertRequestSchema
15781
+ }).strict();
15782
+ var advancedQueryTemplateApplyInputSchema = advancedQueryTemplateInputSchema.extend({
15783
+ request: measurementQueryTemplateApplyRequestSchema,
15784
+ idempotencyKey: advancedIdempotencyKeySchema
15785
+ }).strict();
15786
+ var advancedDeactivateInputSchema = z2.object({
15787
+ request: measurementPlanDeactivateRequestSchema,
15788
+ idempotencyKey: advancedIdempotencyKeySchema
15789
+ }).strict();
15790
+ function readAdvancedMeasurementInput(source) {
15791
+ if (source === void 0) return {};
15792
+ const content = source === "-" ? fs16.readFileSync(0, "utf8") : fs16.readFileSync(source, "utf8");
15793
+ return JSON.parse(content);
15794
+ }
15795
+ var advancedMeasurementCollectionKeys = {
15796
+ "draft-targets": "items",
15797
+ "draft-assignments": "items",
15798
+ "draft-groups": "items",
15799
+ "query-sets": "querySets",
15800
+ "query-templates": "templates"
15801
+ };
15802
+ function isAdvancedMeasurementCollectionOperation(operation) {
15803
+ return operation === "draft-targets" || operation === "draft-assignments" || operation === "draft-groups" || operation === "query-sets" || operation === "query-templates";
15804
+ }
15805
+ function emitAdvancedMeasurementJsonl(operation, result) {
15806
+ if (!isAdvancedMeasurementCollectionOperation(operation) || typeof result !== "object" || result === null || Array.isArray(result)) return false;
15807
+ const collectionKey = advancedMeasurementCollectionKeys[operation];
15808
+ const envelope = result;
15809
+ const candidateRows = envelope[collectionKey];
15810
+ if (!Array.isArray(candidateRows)) return false;
15811
+ const context = {};
15812
+ for (const [key, value] of Object.entries(envelope)) {
15813
+ if (key !== collectionKey) context[key] = value;
15814
+ }
15815
+ emitJsonl([{ kind: "measurement-advanced-header", operation, ...context }]);
15816
+ emitJsonl(candidateRows.map((row) => row));
15817
+ return true;
15818
+ }
15819
+ async function runAdvancedMeasurementOperation(project, operation, source, format) {
15820
+ const input = readAdvancedMeasurementInput(source);
15821
+ const client = createApiClient();
15822
+ let result;
15823
+ switch (operation) {
15824
+ case "setup":
15825
+ advancedEmptyInputSchema.parse(input);
15826
+ result = await client.getMeasurementSetup(project);
15827
+ break;
15828
+ case "overview":
15829
+ result = await client.getMeasurementOverview(project, measurementOverviewQuerySchema.parse(input));
15830
+ break;
15831
+ case "portfolio-summary":
15832
+ result = await client.getMeasurementPortfolioSummary(project, measurementPortfolioSummaryQuerySchema.parse(input));
15833
+ break;
15834
+ case "property-questions":
15835
+ result = await client.getMeasurementPropertyQuestions(project, measurementPropertyQuestionsQuerySchema.parse(input));
15836
+ break;
15837
+ case "question-result":
15838
+ result = await client.getMeasurementQuestionResult(project, measurementQuestionResultQuerySchema.parse(input));
15839
+ break;
15840
+ case "property-competitors":
15841
+ result = await client.getMeasurementPropertyCompetitors(project, measurementPropertyCompetitorsQuerySchema.parse(input));
15842
+ break;
15843
+ case "changes":
15844
+ result = await client.getMeasurementChanges(project, measurementChangesQuerySchema.parse(input));
15845
+ break;
15846
+ case "data-quality":
15847
+ result = await client.getMeasurementDataQuality(project, measurementDataQualityQuerySchema.parse(input));
15848
+ break;
15849
+ case "draft":
15850
+ advancedEmptyInputSchema.parse(input);
15851
+ result = await client.getMeasurementPlanDraft(project);
15852
+ break;
15853
+ case "draft-targets":
15854
+ result = await client.getMeasurementDraftTargets(project, measurementDraftCollectionQuerySchema.parse(input));
15855
+ break;
15856
+ case "draft-assignments":
15857
+ result = await client.getMeasurementDraftAssignments(project, measurementDraftCollectionQuerySchema.parse(input));
15858
+ break;
15859
+ case "draft-groups":
15860
+ result = await client.getMeasurementDraftGroups(project, measurementDraftCollectionQuerySchema.parse(input));
15861
+ break;
15862
+ case "draft-action":
15863
+ result = await runMeasurementDraftAction(client, project, measurementDraftOperationSchema.parse(input));
15864
+ break;
15865
+ case "deactivate": {
15866
+ const parsed = advancedDeactivateInputSchema.parse(input);
15867
+ result = await client.deactivateMeasurementPlan(project, parsed.request, parsed.idempotencyKey);
15868
+ break;
15869
+ }
15870
+ case "query-sets":
15871
+ advancedEmptyInputSchema.parse(input);
15872
+ result = await client.listMeasurementQuerySets(project);
15873
+ break;
15874
+ case "query-set-get": {
15875
+ const parsed = advancedQuerySetInputSchema.parse(input);
15876
+ result = await client.getMeasurementQuerySet(project, parsed.setId);
15877
+ break;
15878
+ }
15879
+ case "query-set-upsert": {
15880
+ const parsed = advancedQuerySetUpsertInputSchema.parse(input);
15881
+ result = await client.upsertMeasurementQuerySet(project, parsed.setId, parsed.request);
15882
+ break;
15883
+ }
15884
+ case "query-set-delete": {
15885
+ const parsed = advancedQuerySetInputSchema.parse(input);
15886
+ result = await client.deleteMeasurementQuerySet(project, parsed.setId);
15887
+ break;
15888
+ }
15889
+ case "query-templates":
15890
+ advancedEmptyInputSchema.parse(input);
15891
+ result = await client.listMeasurementQueryTemplates(project);
15892
+ break;
15893
+ case "query-template-upsert": {
15894
+ const parsed = advancedQueryTemplateUpsertInputSchema.parse(input);
15895
+ result = await client.upsertMeasurementQueryTemplate(project, parsed.templateId, parsed.request);
15896
+ break;
15897
+ }
15898
+ case "query-template-delete": {
15899
+ const parsed = advancedQueryTemplateInputSchema.parse(input);
15900
+ result = await client.deleteMeasurementQueryTemplate(project, parsed.templateId);
15901
+ break;
15902
+ }
15903
+ case "query-template-apply": {
15904
+ const parsed = advancedQueryTemplateApplyInputSchema.parse(input);
15905
+ result = await client.applyMeasurementQueryTemplate(project, parsed.templateId, parsed.request, parsed.idempotencyKey);
15906
+ break;
15907
+ }
15908
+ }
15909
+ if (format === "jsonl" && emitAdvancedMeasurementJsonl(operation, result)) return;
15910
+ console.log(JSON.stringify(result ?? null, null, 2));
15911
+ }
15729
15912
  async function showMeasurementPlan(project, revision) {
15730
15913
  const client = createApiClient();
15731
15914
  console.log(JSON.stringify(revision === void 0 ? await client.getMeasurementPlan(project) : await client.getMeasurementPlanVersion(project, revision), null, 2));
@@ -15745,6 +15928,76 @@ async function publishMeasurementPlan(project, source) {
15745
15928
  async function retireMeasurementPlanSegment(project, stableKey) {
15746
15929
  console.log(JSON.stringify(await createApiClient().retireMeasurementPlanSegment(project, stableKey), null, 2));
15747
15930
  }
15931
+ async function measurementAssignmentRequest(project, opts) {
15932
+ const client = createApiClient();
15933
+ const current = await client.getMeasurementPlanDraft(project);
15934
+ if (!current.draft || !current.etag) {
15935
+ throw new Error(`Project "${project}" has no Advanced Measurement draft. Start setup in the dashboard or create a draft first.`);
15936
+ }
15937
+ const targetKeys = opts.allProperties ? current.draft.authoring.targets.filter((target) => target.status === "included").map((target) => target.stableKey) : opts.targetKeys;
15938
+ return {
15939
+ client,
15940
+ request: {
15941
+ ...targetKeys?.length ? { targetKeys } : {},
15942
+ ...opts.groupKeys?.length ? { groupKeys: opts.groupKeys } : {},
15943
+ queryIds: opts.queryIds
15944
+ }
15945
+ };
15946
+ }
15947
+ async function previewMeasurementPlanAssignments(project, opts) {
15948
+ const { client, request } = await measurementAssignmentRequest(project, opts);
15949
+ console.log(JSON.stringify(await client.previewMeasurementDraftAssignments(project, request), null, 2));
15950
+ }
15951
+ async function applyMeasurementPlanAssignments(project, opts) {
15952
+ const { client, request } = await measurementAssignmentRequest(project, opts);
15953
+ const preview = await client.previewMeasurementDraftAssignments(project, request);
15954
+ const result = await client.applyMeasurementDraftAssignments(
15955
+ project,
15956
+ request,
15957
+ crypto3.randomUUID(),
15958
+ preview.draftEtag
15959
+ );
15960
+ console.log(JSON.stringify({ preview, result }, null, 2));
15961
+ }
15962
+ async function replaceMeasurementPlanAssignments(project, opts) {
15963
+ const { client, request } = await measurementAssignmentRequest(project, opts);
15964
+ const preview = await client.previewMeasurementDraftAssignments(project, request);
15965
+ const result = await client.replaceMeasurementDraftAssignments(
15966
+ project,
15967
+ request,
15968
+ crypto3.randomUUID(),
15969
+ preview.draftEtag
15970
+ );
15971
+ console.log(JSON.stringify({ preview, result }, null, 2));
15972
+ }
15973
+ function readGroupMembershipCsv(source) {
15974
+ return source === "-" ? fs16.readFileSync(0, "utf8") : fs16.readFileSync(source, "utf8");
15975
+ }
15976
+ async function previewMeasurementPlanGroups(project, source) {
15977
+ const preview = await createApiClient().previewMeasurementDraftGroupMembership(project, {
15978
+ csv: readGroupMembershipCsv(source)
15979
+ });
15980
+ console.log(JSON.stringify(preview, null, 2));
15981
+ }
15982
+ async function applyMeasurementPlanGroups(project, source, opts) {
15983
+ const client = createApiClient();
15984
+ const csv = readGroupMembershipCsv(source);
15985
+ const preview = await client.previewMeasurementDraftGroupMembership(project, { csv });
15986
+ if (preview.counts.needsAttention > 0 && !opts.acknowledgeSkipped) {
15987
+ throw new Error(
15988
+ `${preview.counts.needsAttention} CSV rows need attention. Correct them or add --acknowledge-skipped to apply only the selected matched rows.`
15989
+ );
15990
+ }
15991
+ const acceptedRows = opts.acceptAllMatched ? preview.rows.filter((row) => row.status === "matched").map((row) => row.dataRow) : opts.acceptedRows ?? [];
15992
+ if (acceptedRows.length === 0) throw new Error("No matched CSV rows were selected for apply.");
15993
+ const result = await client.applyMeasurementDraftGroupMembership(project, {
15994
+ csv,
15995
+ sourceChecksum: preview.sourceChecksum,
15996
+ previewChecksum: preview.previewChecksum,
15997
+ acceptedRows
15998
+ }, crypto3.randomUUID(), preview.draftEtag);
15999
+ console.log(JSON.stringify({ preview, result }, null, 2));
16000
+ }
15748
16001
  async function discoverMeasurementTargets(project, sitemapUrl, ruleSource, maxUrls) {
15749
16002
  const request = measurementDiscoveryRequestSchema.parse({
15750
16003
  sitemapUrl,
@@ -15801,6 +16054,11 @@ function printMeasurementProperty(response) {
15801
16054
  }
15802
16055
  console.log(lines.join("\n"));
15803
16056
  }
16057
+ function shapedPage(response) {
16058
+ if (response.answers !== void 0) return { shape: MeasurementEvidenceShapes.answers, ...response.answers };
16059
+ if (response.evidence !== void 0) return { shape: MeasurementEvidenceShapes.sources, ...response.evidence };
16060
+ throw systemError("The measurement property evidence response carried neither an evidence nor an answers page.");
16061
+ }
15804
16062
  async function showMeasurementPropertyEvidence(project, opts) {
15805
16063
  const response = await createApiClient().getMeasurementPropertyEvidence(project, {
15806
16064
  targetKey: opts.targetKey,
@@ -15808,19 +16066,22 @@ async function showMeasurementPropertyEvidence(project, opts) {
15808
16066
  ...opts.provider === void 0 ? {} : { provider: opts.provider },
15809
16067
  ...opts.location === void 0 ? {} : { location: opts.location },
15810
16068
  ...opts.runId === void 0 ? {} : { runId: opts.runId },
16069
+ ...opts.shape === void 0 ? {} : { shape: opts.shape },
15811
16070
  ...opts.cursor === void 0 ? {} : { cursor: opts.cursor },
15812
16071
  ...opts.limit === void 0 ? {} : { limit: opts.limit }
15813
16072
  });
15814
16073
  if (opts.format === "jsonl") {
16074
+ const page = shapedPage(response);
15815
16075
  emitJsonl([{
15816
16076
  kind: "measurement-property-evidence-header",
16077
+ shape: page.shape,
15817
16078
  property: response.property,
15818
16079
  queryClass: response.queryClass,
15819
16080
  measurement: response.measurement,
15820
- totalEstimate: response.evidence.totalEstimate ?? null,
15821
- nextCursor: response.evidence.nextCursor ?? null
16081
+ totalEstimate: page.totalEstimate ?? null,
16082
+ nextCursor: page.nextCursor ?? null
15822
16083
  }]);
15823
- emitJsonl(response.evidence.items);
16084
+ emitJsonl(page.items);
15824
16085
  return;
15825
16086
  }
15826
16087
  if (opts.format === "json") {
@@ -15829,6 +16090,10 @@ async function showMeasurementPropertyEvidence(project, opts) {
15829
16090
  }
15830
16091
  printMeasurementPropertyEvidence(response);
15831
16092
  }
16093
+ function signalText(signal) {
16094
+ if (signal === null) return "not measured";
16095
+ return signal ? "yes" : "no";
16096
+ }
15832
16097
  function printMeasurementPropertyEvidence(response) {
15833
16098
  const lines = [];
15834
16099
  lines.push(`${response.property.label} \u2014 ${response.queryClass} questions`);
@@ -15837,18 +16102,28 @@ function printMeasurementPropertyEvidence(response) {
15837
16102
  console.log(lines.join("\n"));
15838
16103
  return;
15839
16104
  }
15840
- const page = response.evidence;
16105
+ const page = shapedPage(response);
16106
+ const answerShape = page.shape === MeasurementEvidenceShapes.answers;
15841
16107
  lines.push(`Measurement: ${response.measurement.state}${response.measurement.displayedRunId ? ` \xB7 run ${response.measurement.displayedRunId}` : ""}`);
15842
16108
  if (page.items.length === 0) {
15843
- lines.push("No source evidence matched this Property in the displayed run.");
16109
+ lines.push(answerShape ? "No answers matched this Property in the displayed run." : "No source evidence matched this Property in the displayed run.");
15844
16110
  console.log(lines.join("\n"));
15845
16111
  return;
15846
16112
  }
15847
- lines.push(`${page.items.length} of ${page.totalEstimate ?? page.items.length} evidence rows`);
16113
+ lines.push(`${page.items.length} of ${page.totalEstimate ?? page.items.length} ${answerShape ? "answers" : "evidence rows"}`);
15848
16114
  lines.push("");
15849
- lines.push(`${"Match".padEnd(14)}${"Engine".padEnd(12)}${"Question".padEnd(40)}URL`);
15850
- for (const item of page.items) {
15851
- lines.push(`${item.classification.padEnd(14)}${item.provider.padEnd(12)}${item.queryText.slice(0, 39).padEnd(40)}${item.sourceUrl}`);
16115
+ if (page.shape === MeasurementEvidenceShapes.answers) {
16116
+ lines.push(`${"Engine".padEnd(12)}${"Question".padEnd(40)}${"Mentioned".padEnd(15)}${"Cited".padEnd(8)}Sources`);
16117
+ for (const item of page.items) {
16118
+ lines.push(
16119
+ `${item.provider.padEnd(12)}${item.queryText.slice(0, 39).padEnd(40)}${signalText(item.mentioned).padEnd(15)}${signalText(item.cited).padEnd(8)}${item.sources.length}`
16120
+ );
16121
+ }
16122
+ } else {
16123
+ lines.push(`${"Match".padEnd(14)}${"Engine".padEnd(12)}${"Question".padEnd(40)}URL`);
16124
+ for (const item of page.items) {
16125
+ lines.push(`${item.classification.padEnd(14)}${item.provider.padEnd(12)}${item.queryText.slice(0, 39).padEnd(40)}${item.sourceUrl}`);
16126
+ }
15852
16127
  }
15853
16128
  if (page.nextCursor) lines.push(`
15854
16129
  More rows: --cursor ${page.nextCursor}`);
@@ -15857,6 +16132,7 @@ More rows: --cursor ${page.nextCursor}`);
15857
16132
 
15858
16133
  // src/cli-commands/measurement-plan.ts
15859
16134
  var QUERY_CLASSES = ["all", "branded", "non-brand"];
16135
+ var EVIDENCE_SHAPES = ["sources", "answers"];
15860
16136
  function queryClassOption(input) {
15861
16137
  const value = getString(input.values, "query-class");
15862
16138
  if (value === void 0) return void 0;
@@ -15864,6 +16140,13 @@ function queryClassOption(input) {
15864
16140
  if (!match) throw usageError(`--query-class must be one of ${QUERY_CLASSES.join(", ")}`);
15865
16141
  return match;
15866
16142
  }
16143
+ function shapeOption(input) {
16144
+ const value = getString(input.values, "shape");
16145
+ if (value === void 0) return void 0;
16146
+ const match = EVIDENCE_SHAPES.find((candidate) => candidate === value);
16147
+ if (!match) throw usageError(`--shape must be one of ${EVIDENCE_SHAPES.join(", ")}`);
16148
+ return match;
16149
+ }
15867
16150
  function propertyScope(input, command, usage) {
15868
16151
  return {
15869
16152
  targetKey: requireStringOption(input, "target-key", { command, usage, message: "--target-key is required" }),
@@ -15881,6 +16164,36 @@ var PROPERTY_SCOPE_OPTIONS = {
15881
16164
  location: stringOption(),
15882
16165
  "run-id": stringOption()
15883
16166
  };
16167
+ var ASSIGNMENT_AUDIENCE_OPTIONS = {
16168
+ group: multiStringOption(),
16169
+ "target-key": multiStringOption(),
16170
+ "all-properties": { type: "boolean" },
16171
+ "query-id": multiStringOption()
16172
+ };
16173
+ function assignmentAudience(input, command, usage) {
16174
+ const project = requireProject(input, command, usage);
16175
+ const groupKeys = getStringArray(input.values, "group")?.map((value) => value.trim()).filter(Boolean);
16176
+ const targetKeys = getStringArray(input.values, "target-key")?.map((value) => value.trim()).filter(Boolean);
16177
+ const queryIds = getStringArray(input.values, "query-id")?.map((value) => value.trim()).filter(Boolean) ?? [];
16178
+ const allProperties = getBoolean(input.values, "all-properties");
16179
+ if (queryIds.length === 0) throw usageError(`Error: at least one --query-id is required
16180
+ Usage: ${usage}`);
16181
+ if (allProperties && ((groupKeys?.length ?? 0) > 0 || (targetKeys?.length ?? 0) > 0)) {
16182
+ throw usageError(`Error: --all-properties cannot be combined with --group or --target-key
16183
+ Usage: ${usage}`);
16184
+ }
16185
+ if (!allProperties && (groupKeys?.length ?? 0) === 0 && (targetKeys?.length ?? 0) === 0) {
16186
+ throw usageError(`Error: select at least one --group, --target-key, or --all-properties
16187
+ Usage: ${usage}`);
16188
+ }
16189
+ return { project, options: { groupKeys, targetKeys, queryIds, allProperties } };
16190
+ }
16191
+ function advancedMeasurementOperation(value, usage) {
16192
+ const operation = ADVANCED_MEASUREMENT_OPERATIONS.find((candidate) => candidate === value);
16193
+ if (operation) return operation;
16194
+ throw usageError(`Error: unsupported Advanced Measurement operation: ${value ?? "(none)"}
16195
+ Usage: ${usage}`);
16196
+ }
15884
16197
  var MEASUREMENT_PLAN_CLI_COMMANDS = [
15885
16198
  { path: ["measurement-plan", "show"], usage: "canonry measurement-plan show <project> [--revision N] [--format json]", options: { revision: stringOption() }, run: async (input) => {
15886
16199
  const value = getString(input.values, "revision");
@@ -15901,6 +16214,95 @@ var MEASUREMENT_PLAN_CLI_COMMANDS = [
15901
16214
  if (!stableKey) throw usageError("stable segment key is required");
15902
16215
  return retireMeasurementPlanSegment(project, stableKey);
15903
16216
  } },
16217
+ {
16218
+ path: ["measurement-plan", "advanced"],
16219
+ usage: "canonry measurement-plan advanced <project> <operation> [<json|->] [--format json|jsonl]",
16220
+ run: (input) => {
16221
+ const usage = "canonry measurement-plan advanced <project> <operation> [<json|->] [--format json|jsonl]";
16222
+ const project = requireProject(input, "measurement-plan.advanced", usage);
16223
+ const operation = advancedMeasurementOperation(input.positionals[1], usage);
16224
+ return runAdvancedMeasurementOperation(project, operation, input.positionals[2], input.format);
16225
+ }
16226
+ },
16227
+ {
16228
+ path: ["measurement-plan", "assignments", "preview"],
16229
+ usage: "canonry measurement-plan assignments preview <project> [--group KEY ...] [--target-key KEY ... | --all-properties] --query-id ID [--query-id ID ...] [--format json]",
16230
+ options: ASSIGNMENT_AUDIENCE_OPTIONS,
16231
+ run: (input) => {
16232
+ const usage = "canonry measurement-plan assignments preview <project> [--group KEY ...] [--target-key KEY ... | --all-properties] --query-id ID [--query-id ID ...]";
16233
+ const { project, options } = assignmentAudience(input, "measurement-plan.assignments.preview", usage);
16234
+ return previewMeasurementPlanAssignments(project, options);
16235
+ }
16236
+ },
16237
+ {
16238
+ path: ["measurement-plan", "assignments", "apply"],
16239
+ usage: "canonry measurement-plan assignments apply <project> [--group KEY ...] [--target-key KEY ... | --all-properties] --query-id ID [--query-id ID ...] [--format json]",
16240
+ options: ASSIGNMENT_AUDIENCE_OPTIONS,
16241
+ run: (input) => {
16242
+ const usage = "canonry measurement-plan assignments apply <project> [--group KEY ...] [--target-key KEY ... | --all-properties] --query-id ID [--query-id ID ...]";
16243
+ const { project, options } = assignmentAudience(input, "measurement-plan.assignments.apply", usage);
16244
+ return applyMeasurementPlanAssignments(project, options);
16245
+ }
16246
+ },
16247
+ {
16248
+ path: ["measurement-plan", "assignments", "replace"],
16249
+ usage: "canonry measurement-plan assignments replace <project> [--group KEY ...] [--target-key KEY ... | --all-properties] --query-id ID [--query-id ID ...] --confirm [--format json]",
16250
+ options: { ...ASSIGNMENT_AUDIENCE_OPTIONS, confirm: { type: "boolean" } },
16251
+ run: (input) => {
16252
+ const usage = "canonry measurement-plan assignments replace <project> [--group KEY ...] [--target-key KEY ... | --all-properties] --query-id ID [--query-id ID ...] --confirm";
16253
+ if (!getBoolean(input.values, "confirm")) throw usageError(`Error: --confirm is required
16254
+ Usage: ${usage}`);
16255
+ const { project, options } = assignmentAudience(input, "measurement-plan.assignments.replace", usage);
16256
+ return replaceMeasurementPlanAssignments(project, options);
16257
+ }
16258
+ },
16259
+ {
16260
+ path: ["measurement-plan", "groups", "preview"],
16261
+ usage: "canonry measurement-plan groups preview <project> <csv|-> [--format json]",
16262
+ run: (input) => {
16263
+ const usage = "canonry measurement-plan groups preview <project> <csv|->";
16264
+ const project = requireProject(input, "measurement-plan.groups.preview", usage);
16265
+ const source = input.positionals[1];
16266
+ if (!source) throw usageError(`Error: CSV file path or - is required
16267
+ Usage: ${usage}`);
16268
+ return previewMeasurementPlanGroups(project, source);
16269
+ }
16270
+ },
16271
+ {
16272
+ path: ["measurement-plan", "groups", "apply"],
16273
+ usage: "canonry measurement-plan groups apply <project> <csv|-> --confirm [--accept-row N ... | --accept-all-matched] [--acknowledge-skipped] [--format json]",
16274
+ options: {
16275
+ confirm: { type: "boolean" },
16276
+ "accept-row": multiStringOption(),
16277
+ "accept-all-matched": { type: "boolean" },
16278
+ "acknowledge-skipped": { type: "boolean" }
16279
+ },
16280
+ run: (input) => {
16281
+ const usage = "canonry measurement-plan groups apply <project> <csv|-> --confirm [--accept-row N ... | --accept-all-matched] [--acknowledge-skipped]";
16282
+ const project = requireProject(input, "measurement-plan.groups.apply", usage);
16283
+ const source = input.positionals[1];
16284
+ if (!source) throw usageError(`Error: CSV file path or - is required
16285
+ Usage: ${usage}`);
16286
+ if (!getBoolean(input.values, "confirm")) throw usageError(`Error: --confirm is required
16287
+ Usage: ${usage}`);
16288
+ const acceptAllMatched = getBoolean(input.values, "accept-all-matched");
16289
+ const rowValues = getStringArray(input.values, "accept-row") ?? [];
16290
+ if (acceptAllMatched === rowValues.length > 0) {
16291
+ throw usageError(`Error: choose exactly one of --accept-row or --accept-all-matched
16292
+ Usage: ${usage}`);
16293
+ }
16294
+ const acceptedRows = rowValues.map((value) => Number(value));
16295
+ if (acceptedRows.some((row) => !Number.isSafeInteger(row) || row < 1)) {
16296
+ throw usageError(`Error: --accept-row must be a positive integer
16297
+ Usage: ${usage}`);
16298
+ }
16299
+ return applyMeasurementPlanGroups(project, source, {
16300
+ acceptedRows,
16301
+ acceptAllMatched,
16302
+ acknowledgeSkipped: getBoolean(input.values, "acknowledge-skipped")
16303
+ });
16304
+ }
16305
+ },
15904
16306
  {
15905
16307
  path: ["measurement-plan", "discover"],
15906
16308
  usage: "canonry measurement-plan discover <project> --sitemap-url <url> --rule <yaml|json|-> [--max-urls N] [--format json]",
@@ -15952,8 +16354,8 @@ var MEASUREMENT_PLAN_CLI_COMMANDS = [
15952
16354
  },
15953
16355
  {
15954
16356
  path: ["measurement-plan", "property-evidence"],
15955
- usage: "canonry measurement-plan property-evidence <project> --target-key <key> [--query-class all|branded|non-brand] [--provider <p>] [--location <l>] [--run-id <id>] [--cursor <c>] [--limit N] [--format json|jsonl]",
15956
- options: { ...PROPERTY_SCOPE_OPTIONS, cursor: stringOption(), limit: stringOption() },
16357
+ usage: "canonry measurement-plan property-evidence <project> --target-key <key> [--query-class all|branded|non-brand] [--provider <p>] [--location <l>] [--run-id <id>] [--shape sources|answers] [--cursor <c>] [--limit N] [--format json|jsonl]",
16358
+ options: { ...PROPERTY_SCOPE_OPTIONS, shape: stringOption(), cursor: stringOption(), limit: stringOption() },
15957
16359
  run: (input) => {
15958
16360
  const usage = "canonry measurement-plan property-evidence <project> --target-key <key>";
15959
16361
  const project = requireProject(input, "measurement-plan.property-evidence", usage);
@@ -15962,8 +16364,10 @@ var MEASUREMENT_PLAN_CLI_COMMANDS = [
15962
16364
  if (limit !== void 0 && (!Number.isInteger(limit) || limit < 1 || limit > 100)) {
15963
16365
  throw usageError("--limit must be an integer from 1 to 100");
15964
16366
  }
16367
+ const shape = shapeOption(input);
15965
16368
  return showMeasurementPropertyEvidence(project, {
15966
16369
  ...propertyScope(input, "measurement-plan.property-evidence", usage),
16370
+ ...shape === void 0 ? {} : { shape },
15967
16371
  cursor: getString(input.values, "cursor"),
15968
16372
  ...limit === void 0 ? {} : { limit }
15969
16373
  });
package/dist/index.js CHANGED
@@ -1,11 +1,11 @@
1
1
  import {
2
2
  createServer
3
- } from "./chunk-Z7B6BRPP.js";
3
+ } from "./chunk-GNKVF6TZ.js";
4
4
  import {
5
5
  loadConfig
6
- } from "./chunk-UQOTEIA6.js";
7
- import "./chunk-ED7C5TWT.js";
8
- import "./chunk-B5H55ZMA.js";
6
+ } from "./chunk-2NTWZHNF.js";
7
+ import "./chunk-ZRUNFIGA.js";
8
+ import "./chunk-BVOU4UJM.js";
9
9
  export {
10
10
  createServer,
11
11
  loadConfig
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  IntelligenceService
3
- } from "./chunk-ED7C5TWT.js";
4
- import "./chunk-B5H55ZMA.js";
3
+ } from "./chunk-ZRUNFIGA.js";
4
+ import "./chunk-BVOU4UJM.js";
5
5
  export {
6
6
  IntelligenceService
7
7
  };
package/dist/mcp.js CHANGED
@@ -3,10 +3,10 @@ import {
3
3
  PACKAGE_VERSION,
4
4
  canonryMcpTools,
5
5
  createApiClient
6
- } from "./chunk-UQOTEIA6.js";
6
+ } from "./chunk-2NTWZHNF.js";
7
7
  import {
8
8
  isReadOnlyKey
9
- } from "./chunk-B5H55ZMA.js";
9
+ } from "./chunk-BVOU4UJM.js";
10
10
 
11
11
  // src/mcp/cli.ts
12
12
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
@@ -110,9 +110,9 @@ var CANONRY_MCP_TOOLKIT_NAMES = ["monitoring", "setup", "gsc", "ga", "gbp", "ads
110
110
  var CANONRY_MCP_TOOLKITS = [
111
111
  {
112
112
  name: "monitoring",
113
- title: "Runs, snapshots, insights, health",
114
- description: "Inspect run history, query snapshots, intelligence insights, and health timelines.",
115
- whenToLoad: "Load when investigating regressions, comparing runs, or reviewing insights and health history."
113
+ title: "Measurement, runs, insights, health",
114
+ description: "Inspect portfolio and Property measurement, question results, run history, intelligence insights, and health timelines.",
115
+ whenToLoad: "Load when finding weak Properties, reviewing answers and competitors, checking data quality, comparing runs, or investigating regressions."
116
116
  },
117
117
  {
118
118
  name: "setup",