@canonry/canonry 4.141.0 → 4.143.0

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 (28) hide show
  1. package/assets/agent-workspace/skills/canonry/references/canonry-cli.md +45 -5
  2. package/assets/assets/{AuditHistoryPanel-DlyLhzqq.js → AuditHistoryPanel--kNrRAQm.js} +1 -1
  3. package/assets/assets/{BacklinksPage-DNxtwQBF.js → BacklinksPage-CtW1w9lh.js} +1 -1
  4. package/assets/assets/{ChartPrimitives-BStLR_NC.js → ChartPrimitives-C-nMEqdu.js} +1 -1
  5. package/assets/assets/{HistoryPage-CIcCgoWK.js → HistoryPage-CAPJDSbc.js} +1 -1
  6. package/assets/assets/ProjectPage-79R3wJW6.js +9 -0
  7. package/assets/assets/{RunRow-C0mFtLlc.js → RunRow-aDzTzGSK.js} +1 -1
  8. package/assets/assets/{RunsPage-C-yo0yoj.js → RunsPage-Dy9oWMBK.js} +1 -1
  9. package/assets/assets/{SettingsPage-jg4MXOuo.js → SettingsPage-DTAs1BrZ.js} +1 -1
  10. package/assets/assets/{TrafficPage-CnYHIg8t.js → TrafficPage-B4ADqeKG.js} +1 -1
  11. package/assets/assets/{TrafficSourceDetailPage-CEdyQT2P.js → TrafficSourceDetailPage-CFcoL_PR.js} +1 -1
  12. package/assets/assets/{arrow-left-DUv0imIl.js → arrow-left-DV9xcX1v.js} +1 -1
  13. package/assets/assets/{extract-error-message-CCOGDwlm.js → extract-error-message-DXtgw8Q8.js} +1 -1
  14. package/assets/assets/{index-BDo9nl4O.css → index-CYA3jd24.css} +1 -1
  15. package/assets/assets/index-H2iFFrr1.js +213 -0
  16. package/assets/assets/{trash-2-1Yg9W-vs.js → trash-2-DMV6uGU1.js} +1 -1
  17. package/assets/index.html +2 -2
  18. package/dist/{chunk-ZCFQGF3V.js → chunk-3G5B3IMZ.js} +319 -7
  19. package/dist/{chunk-OJOA425V.js → chunk-KUPTGRME.js} +4342 -3042
  20. package/dist/{chunk-HXXO2AF5.js → chunk-TJ6SDLXL.js} +4 -4
  21. package/dist/{chunk-2LUSZFB6.js → chunk-VN3CI6K6.js} +3339 -1226
  22. package/dist/cli.js +187 -65
  23. package/dist/index.js +4 -4
  24. package/dist/{intelligence-service-4HQIUC7U.js → intelligence-service-V6JYDYGF.js} +2 -2
  25. package/dist/mcp.js +2 -2
  26. package/package.json +9 -9
  27. package/assets/assets/ProjectPage-BSI3Qum9.js +0 -8
  28. package/assets/assets/index-D6EP4dQs.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-HXXO2AF5.js";
33
+ } from "./chunk-TJ6SDLXL.js";
34
34
  import {
35
35
  CliError,
36
36
  EXIT_SYSTEM_ERROR,
@@ -47,7 +47,7 @@ import {
47
47
  saveConfig,
48
48
  saveConfigPatch,
49
49
  usageError
50
- } from "./chunk-ZCFQGF3V.js";
50
+ } from "./chunk-3G5B3IMZ.js";
51
51
  import {
52
52
  apiKeys,
53
53
  createClient,
@@ -55,7 +55,7 @@ import {
55
55
  projects,
56
56
  queries,
57
57
  renderReportHtml
58
- } from "./chunk-2LUSZFB6.js";
58
+ } from "./chunk-VN3CI6K6.js";
59
59
  import {
60
60
  AdsDeliverySnapshotStatuses,
61
61
  AdsHistoricalCampaignRollupStatuses,
@@ -96,12 +96,15 @@ import {
96
96
  formatMicros,
97
97
  formatRatio,
98
98
  formatRunErrorOneLine,
99
+ measurementDiscoveryRequestSchema,
100
+ measurementDiscoveryRuleSchema,
101
+ measurementPlanInputSchema,
99
102
  normalizeProjectAliases,
100
103
  notificationEventSchema,
101
104
  providerQuotaPolicySchema,
102
105
  resolveProviderInput,
103
106
  winnabilityClassSchema
104
- } from "./chunk-OJOA425V.js";
107
+ } from "./chunk-KUPTGRME.js";
105
108
 
106
109
  // src/cli.ts
107
110
  import { pathToFileURL } from "url";
@@ -3824,6 +3827,16 @@ Usage: ${usage}`, {
3824
3827
  function getClient7() {
3825
3828
  return createApiClient();
3826
3829
  }
3830
+ function rangeParams(opts, extra) {
3831
+ const params = { ...extra };
3832
+ if (opts?.window) params.window = opts.window;
3833
+ if (opts?.startDate) params.startDate = opts.startDate;
3834
+ if (opts?.endDate) params.endDate = opts.endDate;
3835
+ return Object.keys(params).length > 0 ? params : void 0;
3836
+ }
3837
+ function isRangeScoped(opts) {
3838
+ return Boolean(opts?.window || opts?.startDate || opts?.endDate);
3839
+ }
3827
3840
  async function gaConnect(project, opts) {
3828
3841
  if (!opts.propertyId) {
3829
3842
  throw new CliError({
@@ -3837,9 +3850,9 @@ async function gaConnect(project, opts) {
3837
3850
  propertyId: opts.propertyId
3838
3851
  };
3839
3852
  if (opts.keyFile) {
3840
- const fs16 = await import("fs");
3853
+ const fs17 = await import("fs");
3841
3854
  try {
3842
- const content = fs16.readFileSync(opts.keyFile, "utf-8");
3855
+ const content = fs17.readFileSync(opts.keyFile, "utf-8");
3843
3856
  JSON.parse(content);
3844
3857
  body.keyJson = content;
3845
3858
  } catch (e) {
@@ -3925,10 +3938,8 @@ async function gaSync(project, opts) {
3925
3938
  }
3926
3939
  async function gaTraffic(project, opts) {
3927
3940
  const client = getClient7();
3928
- const params = {};
3929
- if (opts?.limit) params.limit = String(opts.limit);
3930
- if (opts?.window) params.window = opts.window;
3931
- const result = await client.gaTraffic(project, Object.keys(params).length > 0 ? params : void 0);
3941
+ const params = rangeParams(opts, opts?.limit ? { limit: String(opts.limit) } : void 0);
3942
+ const result = await client.gaTraffic(project, params);
3932
3943
  if (isMachineFormat(opts?.format)) {
3933
3944
  console.log(JSON.stringify(result, null, 2));
3934
3945
  return;
@@ -3937,7 +3948,7 @@ async function gaTraffic(project, opts) {
3937
3948
  if (!result.lastSyncedAt) {
3938
3949
  console.log('No GA4 traffic data. Run "canonry ga sync <project>" first.');
3939
3950
  } else {
3940
- console.log(`No GA4 traffic data for the selected period.${opts?.window ? ` Try a wider window or omit --window.` : ""}`);
3951
+ console.log(`No GA4 traffic data for the selected period.${isRangeScoped(opts) ? " Try a wider range, or omit --window / --start / --end." : ""}`);
3941
3952
  }
3942
3953
  return;
3943
3954
  }
@@ -4061,16 +4072,16 @@ async function gaMeasurementAnalysis(project, opts) {
4061
4072
  }
4062
4073
  async function gaAiReferralHistory(project, opts) {
4063
4074
  const client = getClient7();
4064
- const result = await client.gaAiReferralHistory(project, opts?.window ? { window: opts.window } : void 0);
4075
+ const result = await client.gaAiReferralHistory(project, rangeParams(opts));
4065
4076
  if (opts?.format === "json") {
4066
4077
  console.log(JSON.stringify(result, null, 2));
4067
4078
  return;
4068
4079
  } else if (opts?.format === "jsonl") {
4069
- emitJsonl(result.map((row) => ({ project, window: opts?.window, ...row })));
4080
+ emitJsonl(result.map((row) => ({ project, window: opts?.window, startDate: opts?.startDate, endDate: opts?.endDate, ...row })));
4070
4081
  return;
4071
4082
  }
4072
4083
  if (result.length === 0) {
4073
- console.log(`No AI referral history.${opts?.window ? " Try a wider window or omit --window." : ' Run "canonry ga sync <project>" first.'}`);
4084
+ console.log(`No AI referral history.${isRangeScoped(opts) ? " Try a wider range, or omit --window / --start / --end." : ' Run "canonry ga sync <project>" first.'}`);
4074
4085
  return;
4075
4086
  }
4076
4087
  const dateWidth = 12;
@@ -4089,16 +4100,16 @@ async function gaAiReferralHistory(project, opts) {
4089
4100
  }
4090
4101
  async function gaAiReferralDaily(project, opts) {
4091
4102
  const client = getClient7();
4092
- const result = await client.gaAiReferralDaily(project, opts?.window ? { window: opts.window } : void 0);
4103
+ const result = await client.gaAiReferralDaily(project, rangeParams(opts));
4093
4104
  if (opts?.format === "json") {
4094
4105
  console.log(JSON.stringify(result, null, 2));
4095
4106
  return;
4096
4107
  } else if (opts?.format === "jsonl") {
4097
- emitJsonl(result.days.map((day) => ({ project, window: opts?.window, ...day })));
4108
+ emitJsonl(result.days.map((day) => ({ project, window: opts?.window, startDate: opts?.startDate, endDate: opts?.endDate, ...day })));
4098
4109
  return;
4099
4110
  }
4100
4111
  if (result.days.length === 0) {
4101
- console.log(`No AI referral sessions.${opts?.window ? " Try a wider window or omit --window." : ' Run "canonry ga sync <project>" first.'}`);
4112
+ console.log(`No AI referral sessions.${isRangeScoped(opts) ? " Try a wider range, or omit --window / --start / --end." : ' Run "canonry ga sync <project>" first.'}`);
4102
4113
  return;
4103
4114
  }
4104
4115
  const dateWidth = 12;
@@ -4119,16 +4130,16 @@ async function gaAiReferralDaily(project, opts) {
4119
4130
  }
4120
4131
  async function gaSocialReferralHistory(project, opts) {
4121
4132
  const client = getClient7();
4122
- const result = await client.gaSocialReferralHistory(project, opts?.window ? { window: opts.window } : void 0);
4133
+ const result = await client.gaSocialReferralHistory(project, rangeParams(opts));
4123
4134
  if (opts?.format === "json") {
4124
4135
  console.log(JSON.stringify(result, null, 2));
4125
4136
  return;
4126
4137
  } else if (opts?.format === "jsonl") {
4127
- emitJsonl(result.map((row) => ({ project, window: opts?.window, ...row })));
4138
+ emitJsonl(result.map((row) => ({ project, window: opts?.window, startDate: opts?.startDate, endDate: opts?.endDate, ...row })));
4128
4139
  return;
4129
4140
  }
4130
4141
  if (result.length === 0) {
4131
- console.log(`No social referral history.${opts?.window ? " Try a wider window or omit --window." : ' Run "canonry ga sync <project>" first.'}`);
4142
+ console.log(`No social referral history.${isRangeScoped(opts) ? " Try a wider range, or omit --window / --start / --end." : ' Run "canonry ga sync <project>" first.'}`);
4132
4143
  return;
4133
4144
  }
4134
4145
  const dateWidth = 12;
@@ -4147,16 +4158,16 @@ async function gaSocialReferralHistory(project, opts) {
4147
4158
  }
4148
4159
  async function gaSessionHistory(project, opts) {
4149
4160
  const client = getClient7();
4150
- const result = await client.gaSessionHistory(project, opts?.window ? { window: opts.window } : void 0);
4161
+ const result = await client.gaSessionHistory(project, rangeParams(opts));
4151
4162
  if (opts?.format === "json") {
4152
4163
  console.log(JSON.stringify(result, null, 2));
4153
4164
  return;
4154
4165
  } else if (opts?.format === "jsonl") {
4155
- emitJsonl(result.map((row) => ({ project, window: opts?.window, ...row })));
4166
+ emitJsonl(result.map((row) => ({ project, window: opts?.window, startDate: opts?.startDate, endDate: opts?.endDate, ...row })));
4156
4167
  return;
4157
4168
  }
4158
4169
  if (result.length === 0) {
4159
- console.log(`No session history.${opts?.window ? " Try a wider window or omit --window." : ' Run "canonry ga sync <project>" first.'}`);
4170
+ console.log(`No session history.${isRangeScoped(opts) ? " Try a wider range, or omit --window / --start / --end." : ' Run "canonry ga sync <project>" first.'}`);
4160
4171
  return;
4161
4172
  }
4162
4173
  const dateWidth = 12;
@@ -4449,6 +4460,19 @@ async function gaAttribution(project, opts) {
4449
4460
  }
4450
4461
 
4451
4462
  // src/cli-commands/ga.ts
4463
+ var RANGE_OPTIONS = {
4464
+ window: stringOption(),
4465
+ start: stringOption(),
4466
+ end: stringOption()
4467
+ };
4468
+ var RANGE_USAGE = "[--window 30d] [--start YYYY-MM-DD] [--end YYYY-MM-DD]";
4469
+ function rangeValues(values) {
4470
+ return {
4471
+ window: getString(values, "window"),
4472
+ startDate: getString(values, "start"),
4473
+ endDate: getString(values, "end")
4474
+ };
4475
+ }
4452
4476
  var GA_CLI_COMMANDS = [
4453
4477
  {
4454
4478
  path: ["ga", "connect"],
@@ -4530,19 +4554,18 @@ var GA_CLI_COMMANDS = [
4530
4554
  },
4531
4555
  {
4532
4556
  path: ["ga", "traffic"],
4533
- usage: "canonry ga traffic <project> [--limit 50] [--window 30d] [--format json]",
4557
+ usage: `canonry ga traffic <project> [--limit 50] ${RANGE_USAGE} [--format json]`,
4534
4558
  options: {
4535
4559
  limit: stringOption(),
4536
- window: stringOption()
4560
+ ...RANGE_OPTIONS
4537
4561
  },
4538
4562
  run: async (input) => {
4539
- const project = requireProject(input, "ga.traffic", "canonry ga traffic <project> [--limit 50] [--window 30d] [--format json]");
4563
+ const project = requireProject(input, "ga.traffic", `canonry ga traffic <project> [--limit 50] ${RANGE_USAGE} [--format json]`);
4540
4564
  const limitStr = getString(input.values, "limit");
4541
4565
  const limit = limitStr ? parseInt(limitStr, 10) : void 0;
4542
- const window = getString(input.values, "window");
4543
4566
  await gaTraffic(project, {
4544
4567
  limit,
4545
- window,
4568
+ ...rangeValues(input.values),
4546
4569
  format: input.format
4547
4570
  });
4548
4571
  }
@@ -4557,56 +4580,48 @@ var GA_CLI_COMMANDS = [
4557
4580
  },
4558
4581
  {
4559
4582
  path: ["ga", "ai-referral-history"],
4560
- usage: "canonry ga ai-referral-history <project> [--window 30d] [--format json]",
4561
- options: {
4562
- window: stringOption()
4563
- },
4583
+ usage: `canonry ga ai-referral-history <project> ${RANGE_USAGE} [--format json]`,
4584
+ options: { ...RANGE_OPTIONS },
4564
4585
  run: async (input) => {
4565
- const project = requireProject(input, "ga.ai-referral-history", "canonry ga ai-referral-history <project> [--window 30d] [--format json]");
4586
+ const project = requireProject(input, "ga.ai-referral-history", `canonry ga ai-referral-history <project> ${RANGE_USAGE} [--format json]`);
4566
4587
  await gaAiReferralHistory(project, {
4567
- window: getString(input.values, "window"),
4588
+ ...rangeValues(input.values),
4568
4589
  format: input.format
4569
4590
  });
4570
4591
  }
4571
4592
  },
4572
4593
  {
4573
4594
  path: ["ga", "ai-referral-daily"],
4574
- usage: "canonry ga ai-referral-daily <project> [--window 30d] [--format json]",
4575
- options: {
4576
- window: stringOption()
4577
- },
4595
+ usage: `canonry ga ai-referral-daily <project> ${RANGE_USAGE} [--format json]`,
4596
+ options: { ...RANGE_OPTIONS },
4578
4597
  run: async (input) => {
4579
- const project = requireProject(input, "ga.ai-referral-daily", "canonry ga ai-referral-daily <project> [--window 30d] [--format json]");
4598
+ const project = requireProject(input, "ga.ai-referral-daily", `canonry ga ai-referral-daily <project> ${RANGE_USAGE} [--format json]`);
4580
4599
  await gaAiReferralDaily(project, {
4581
- window: getString(input.values, "window"),
4600
+ ...rangeValues(input.values),
4582
4601
  format: input.format
4583
4602
  });
4584
4603
  }
4585
4604
  },
4586
4605
  {
4587
4606
  path: ["ga", "social-referral-history"],
4588
- usage: "canonry ga social-referral-history <project> [--window 30d] [--format json]",
4589
- options: {
4590
- window: stringOption()
4591
- },
4607
+ usage: `canonry ga social-referral-history <project> ${RANGE_USAGE} [--format json]`,
4608
+ options: { ...RANGE_OPTIONS },
4592
4609
  run: async (input) => {
4593
- const project = requireProject(input, "ga.social-referral-history", "canonry ga social-referral-history <project> [--window 30d] [--format json]");
4610
+ const project = requireProject(input, "ga.social-referral-history", `canonry ga social-referral-history <project> ${RANGE_USAGE} [--format json]`);
4594
4611
  await gaSocialReferralHistory(project, {
4595
- window: getString(input.values, "window"),
4612
+ ...rangeValues(input.values),
4596
4613
  format: input.format
4597
4614
  });
4598
4615
  }
4599
4616
  },
4600
4617
  {
4601
4618
  path: ["ga", "session-history"],
4602
- usage: "canonry ga session-history <project> [--window 30d] [--format json]",
4603
- options: {
4604
- window: stringOption()
4605
- },
4619
+ usage: `canonry ga session-history <project> ${RANGE_USAGE} [--format json]`,
4620
+ options: { ...RANGE_OPTIONS },
4606
4621
  run: async (input) => {
4607
- const project = requireProject(input, "ga.session-history", "canonry ga session-history <project> [--window 30d] [--format json]");
4622
+ const project = requireProject(input, "ga.session-history", `canonry ga session-history <project> ${RANGE_USAGE} [--format json]`);
4608
4623
  await gaSessionHistory(project, {
4609
- window: getString(input.values, "window"),
4624
+ ...rangeValues(input.values),
4610
4625
  format: input.format
4611
4626
  });
4612
4627
  }
@@ -5286,9 +5301,9 @@ async function trafficConnectWordpress(project, opts) {
5286
5301
  }
5287
5302
  let applicationPassword = opts.appPassword?.trim() ?? "";
5288
5303
  if (!applicationPassword && opts.appPasswordFile) {
5289
- const fs16 = await import("fs");
5304
+ const fs17 = await import("fs");
5290
5305
  try {
5291
- applicationPassword = fs16.readFileSync(opts.appPasswordFile, "utf-8").trim();
5306
+ applicationPassword = fs17.readFileSync(opts.appPasswordFile, "utf-8").trim();
5292
5307
  } catch (e) {
5293
5308
  const msg = e instanceof Error ? e.message : String(e);
5294
5309
  throw new CliError({
@@ -5344,10 +5359,10 @@ async function trafficConnectCloudRun(project, opts) {
5344
5359
  details: { project }
5345
5360
  });
5346
5361
  }
5347
- const fs16 = await import("fs");
5362
+ const fs17 = await import("fs");
5348
5363
  let keyJson;
5349
5364
  try {
5350
- keyJson = fs16.readFileSync(opts.serviceAccountKey, "utf-8");
5365
+ keyJson = fs17.readFileSync(opts.serviceAccountKey, "utf-8");
5351
5366
  JSON.parse(keyJson);
5352
5367
  } catch (e) {
5353
5368
  const msg = e instanceof Error ? e.message : String(e);
@@ -5407,9 +5422,9 @@ async function trafficConnectVercel(project, opts) {
5407
5422
  }
5408
5423
  let token = opts.token?.trim() ?? "";
5409
5424
  if (!token && opts.tokenFile) {
5410
- const fs16 = await import("fs");
5425
+ const fs17 = await import("fs");
5411
5426
  try {
5412
- token = fs16.readFileSync(opts.tokenFile, "utf-8").trim();
5427
+ token = fs17.readFileSync(opts.tokenFile, "utf-8").trim();
5413
5428
  } catch (e) {
5414
5429
  const msg = e instanceof Error ? e.message : String(e);
5415
5430
  throw new CliError({
@@ -14106,12 +14121,12 @@ async function wordpressSetMeta(project, body) {
14106
14121
  printPageDetail(result);
14107
14122
  }
14108
14123
  async function wordpressBulkSetMeta(project, opts) {
14109
- const fs16 = await import("fs/promises");
14124
+ const fs17 = await import("fs/promises");
14110
14125
  const path12 = await import("path");
14111
14126
  const filePath = path12.resolve(opts.from);
14112
14127
  let raw;
14113
14128
  try {
14114
- raw = await fs16.readFile(filePath, "utf8");
14129
+ raw = await fs17.readFile(filePath, "utf8");
14115
14130
  } catch {
14116
14131
  throw new CliError({
14117
14132
  code: "FILE_READ_ERROR",
@@ -14208,13 +14223,13 @@ async function wordpressSetSchema(project, body) {
14208
14223
  printManualAssist(`Schema update for "${body.slug}"`, result);
14209
14224
  }
14210
14225
  async function wordpressSchemaDeploy(project, opts) {
14211
- const fs16 = await import("fs/promises");
14226
+ const fs17 = await import("fs/promises");
14212
14227
  const path12 = await import("path");
14213
14228
  const yaml = await loadYamlModule();
14214
14229
  const filePath = path12.resolve(opts.profile);
14215
14230
  let raw;
14216
14231
  try {
14217
- raw = await fs16.readFile(filePath, "utf8");
14232
+ raw = await fs17.readFile(filePath, "utf8");
14218
14233
  } catch {
14219
14234
  throw new CliError({
14220
14235
  code: "FILE_READ_ERROR",
@@ -14319,13 +14334,13 @@ async function wordpressOnboard(project, opts) {
14319
14334
  }
14320
14335
  let profileData;
14321
14336
  if (opts.profile) {
14322
- const fs16 = await import("fs/promises");
14337
+ const fs17 = await import("fs/promises");
14323
14338
  const path12 = await import("path");
14324
14339
  const yaml = await loadYamlModule();
14325
14340
  const filePath = path12.resolve(opts.profile);
14326
14341
  let raw;
14327
14342
  try {
14328
- raw = await fs16.readFile(filePath, "utf8");
14343
+ raw = await fs17.readFile(filePath, "utf8");
14329
14344
  } catch {
14330
14345
  throw new CliError({
14331
14346
  code: "FILE_READ_ERROR",
@@ -15439,6 +15454,112 @@ Usage: ${usage}`, {
15439
15454
  }
15440
15455
  ];
15441
15456
 
15457
+ // src/commands/measurement-plan.ts
15458
+ import fs16 from "fs";
15459
+ import { parse } from "yaml";
15460
+ function readPlan(source) {
15461
+ const content = source === "-" ? fs16.readFileSync(0, "utf8") : fs16.readFileSync(source, "utf8");
15462
+ const parsed = source.endsWith(".json") ? JSON.parse(content) : parse(content);
15463
+ return measurementPlanInputSchema.parse(parsed);
15464
+ }
15465
+ function readDiscoveryRule(source) {
15466
+ const content = source === "-" ? fs16.readFileSync(0, "utf8") : fs16.readFileSync(source, "utf8");
15467
+ const parsed = source.endsWith(".json") ? JSON.parse(content) : parse(content);
15468
+ return measurementDiscoveryRuleSchema.parse(parsed);
15469
+ }
15470
+ async function showMeasurementPlan(project, revision) {
15471
+ const client = createApiClient();
15472
+ console.log(JSON.stringify(revision === void 0 ? await client.getMeasurementPlan(project) : await client.getMeasurementPlanVersion(project, revision), null, 2));
15473
+ }
15474
+ async function listMeasurementPlanVersions(project) {
15475
+ console.log(JSON.stringify(await createApiClient().listMeasurementPlanVersions(project), null, 2));
15476
+ }
15477
+ async function publishMeasurementPlan(project, source) {
15478
+ const client = createApiClient();
15479
+ const plan = readPlan(source);
15480
+ const current = await client.getMeasurementPlan(project);
15481
+ console.log(JSON.stringify(await client.publishMeasurementPlan(project, {
15482
+ expectedActiveRevision: current.active?.revision ?? null,
15483
+ plan
15484
+ }), null, 2));
15485
+ }
15486
+ async function retireMeasurementPlanSegment(project, stableKey) {
15487
+ console.log(JSON.stringify(await createApiClient().retireMeasurementPlanSegment(project, stableKey), null, 2));
15488
+ }
15489
+ async function discoverMeasurementTargets(project, sitemapUrl, ruleSource, maxUrls) {
15490
+ const request = measurementDiscoveryRequestSchema.parse({
15491
+ sitemapUrl,
15492
+ rule: readDiscoveryRule(ruleSource),
15493
+ ...maxUrls === void 0 ? {} : { maxUrls }
15494
+ });
15495
+ console.log(JSON.stringify(await createApiClient().discoverMeasurementTargets(project, request), null, 2));
15496
+ }
15497
+ async function showMeasurementReport(project, revision) {
15498
+ console.log(JSON.stringify(await createApiClient().getMeasurementReport(project, revision), null, 2));
15499
+ }
15500
+
15501
+ // src/cli-commands/measurement-plan.ts
15502
+ var MEASUREMENT_PLAN_CLI_COMMANDS = [
15503
+ { path: ["measurement-plan", "show"], usage: "canonry measurement-plan show <project> [--revision N] [--format json]", options: { revision: stringOption() }, run: async (input) => {
15504
+ const value = getString(input.values, "revision");
15505
+ const revision = value === void 0 ? void 0 : Number(value);
15506
+ if (revision !== void 0 && (!Number.isInteger(revision) || revision <= 0)) throw usageError("--revision must be a positive integer");
15507
+ await showMeasurementPlan(requireProject(input, "measurement-plan.show", "canonry measurement-plan show <project> [--revision N]"), revision);
15508
+ } },
15509
+ { path: ["measurement-plan", "versions"], usage: "canonry measurement-plan versions <project> [--format json]", run: (input) => listMeasurementPlanVersions(requireProject(input, "measurement-plan.versions", "canonry measurement-plan versions <project>")) },
15510
+ { path: ["measurement-plan", "publish"], usage: "canonry measurement-plan publish <project> <yaml|json|-> [--format json]", run: (input) => {
15511
+ const project = requireProject(input, "measurement-plan.publish", "canonry measurement-plan publish <project> <yaml|json|->");
15512
+ const source = input.positionals[1];
15513
+ if (!source) throw usageError("plan file path or - is required");
15514
+ return publishMeasurementPlan(project, source);
15515
+ } },
15516
+ { path: ["measurement-plan", "retire"], usage: "canonry measurement-plan retire <project> <stable-key> [--format json]", run: (input) => {
15517
+ const project = requireProject(input, "measurement-plan.retire", "canonry measurement-plan retire <project> <stable-key>");
15518
+ const stableKey = input.positionals[1];
15519
+ if (!stableKey) throw usageError("stable segment key is required");
15520
+ return retireMeasurementPlanSegment(project, stableKey);
15521
+ } },
15522
+ {
15523
+ path: ["measurement-plan", "discover"],
15524
+ usage: "canonry measurement-plan discover <project> --sitemap-url <url> --rule <yaml|json|-> [--max-urls N] [--format json]",
15525
+ options: { "sitemap-url": stringOption(), rule: stringOption(), "max-urls": stringOption() },
15526
+ run: (input) => {
15527
+ const usage = "canonry measurement-plan discover <project> --sitemap-url <url> --rule <yaml|json|-> [--max-urls N]";
15528
+ const project = requireProject(input, "measurement-plan.discover", usage);
15529
+ const sitemapUrl = requireStringOption(input, "sitemap-url", {
15530
+ command: "measurement-plan.discover",
15531
+ usage,
15532
+ message: "--sitemap-url is required"
15533
+ });
15534
+ const rule = requireStringOption(input, "rule", {
15535
+ command: "measurement-plan.discover",
15536
+ usage,
15537
+ message: "--rule is required"
15538
+ });
15539
+ const maxUrlsValue = getString(input.values, "max-urls");
15540
+ const maxUrls = maxUrlsValue === void 0 ? void 0 : Number(maxUrlsValue);
15541
+ if (maxUrls !== void 0 && (!Number.isInteger(maxUrls) || maxUrls < 1 || maxUrls > 1e4)) {
15542
+ throw usageError("--max-urls must be an integer from 1 to 10000");
15543
+ }
15544
+ return discoverMeasurementTargets(project, sitemapUrl, rule, maxUrls);
15545
+ }
15546
+ },
15547
+ {
15548
+ path: ["measurement-plan", "report"],
15549
+ usage: "canonry measurement-plan report <project> --revision N [--format json]",
15550
+ options: { revision: stringOption() },
15551
+ run: (input) => {
15552
+ const project = requireProject(input, "measurement-plan.report", "canonry measurement-plan report <project> --revision N");
15553
+ const value = getString(input.values, "revision");
15554
+ const revision = value === void 0 ? void 0 : Number(value);
15555
+ if (revision === void 0 || !Number.isInteger(revision) || revision <= 0) {
15556
+ throw usageError("--revision must be a positive integer");
15557
+ }
15558
+ return showMeasurementReport(project, revision);
15559
+ }
15560
+ }
15561
+ ];
15562
+
15442
15563
  // src/cli-commands.ts
15443
15564
  var REGISTERED_CLI_COMMANDS = [
15444
15565
  ...BACKFILL_CLI_COMMANDS,
@@ -15475,7 +15596,8 @@ var REGISTERED_CLI_COMMANDS = [
15475
15596
  ...TECHNICAL_AEO_CLI_COMMANDS,
15476
15597
  ...DOCTOR_CLI_COMMANDS,
15477
15598
  ...GET_CLI_COMMANDS,
15478
- ...MCP_CLI_COMMANDS
15599
+ ...MCP_CLI_COMMANDS,
15600
+ ...MEASUREMENT_PLAN_CLI_COMMANDS
15479
15601
  ];
15480
15602
 
15481
15603
  // src/setup-nudge.ts
package/dist/index.js CHANGED
@@ -1,11 +1,11 @@
1
1
  import {
2
2
  createServer
3
- } from "./chunk-HXXO2AF5.js";
3
+ } from "./chunk-TJ6SDLXL.js";
4
4
  import {
5
5
  loadConfig
6
- } from "./chunk-ZCFQGF3V.js";
7
- import "./chunk-2LUSZFB6.js";
8
- import "./chunk-OJOA425V.js";
6
+ } from "./chunk-3G5B3IMZ.js";
7
+ import "./chunk-VN3CI6K6.js";
8
+ import "./chunk-KUPTGRME.js";
9
9
  export {
10
10
  createServer,
11
11
  loadConfig
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  IntelligenceService
3
- } from "./chunk-2LUSZFB6.js";
4
- import "./chunk-OJOA425V.js";
3
+ } from "./chunk-VN3CI6K6.js";
4
+ import "./chunk-KUPTGRME.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-ZCFQGF3V.js";
6
+ } from "./chunk-3G5B3IMZ.js";
7
7
  import {
8
8
  isReadOnlyKey
9
- } from "./chunk-OJOA425V.js";
9
+ } from "./chunk-KUPTGRME.js";
10
10
 
11
11
  // src/mcp/cli.ts
12
12
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@canonry/canonry",
3
- "version": "4.141.0",
3
+ "version": "4.143.0",
4
4
  "type": "module",
5
5
  "description": "Agent-first open-source AEO operating platform - track how answer engines cite your domain",
6
6
  "license": "FSL-1.1-ALv2",
@@ -65,27 +65,27 @@
65
65
  "@types/node-cron": "^3.0.11",
66
66
  "tsup": "^8.5.1",
67
67
  "tsx": "^4.19.0",
68
- "@ainyc/canonry-config": "0.0.0",
69
68
  "@ainyc/canonry-api-client": "0.0.0",
70
- "@ainyc/canonry-contracts": "0.0.0",
71
- "@ainyc/canonry-db": "0.0.0",
72
69
  "@ainyc/canonry-api-routes": "0.0.0",
70
+ "@ainyc/canonry-db": "0.0.0",
71
+ "@ainyc/canonry-contracts": "0.0.0",
72
+ "@ainyc/canonry-config": "0.0.0",
73
73
  "@ainyc/canonry-integration-bing": "0.0.0",
74
- "@ainyc/canonry-integration-cloud-run": "0.0.0",
75
74
  "@ainyc/canonry-integration-openai-ads": "0.0.0",
75
+ "@ainyc/canonry-integration-cloud-run": "0.0.0",
76
76
  "@ainyc/canonry-integration-commoncrawl": "0.0.0",
77
77
  "@ainyc/canonry-integration-google": "0.0.0",
78
78
  "@ainyc/canonry-integration-google-business-profile": "0.0.0",
79
- "@ainyc/canonry-integration-google-places": "0.0.0",
80
79
  "@ainyc/canonry-integration-traffic": "0.0.0",
80
+ "@ainyc/canonry-integration-wordpress": "0.0.0",
81
81
  "@ainyc/canonry-intelligence": "0.0.0",
82
+ "@ainyc/canonry-integration-google-places": "0.0.0",
82
83
  "@ainyc/canonry-provider-cdp": "0.0.0",
83
- "@ainyc/canonry-provider-gemini": "0.0.0",
84
84
  "@ainyc/canonry-provider-claude": "0.0.0",
85
+ "@ainyc/canonry-provider-perplexity": "0.0.0",
85
86
  "@ainyc/canonry-provider-local": "0.0.0",
86
87
  "@ainyc/canonry-provider-openai": "0.0.0",
87
- "@ainyc/canonry-integration-wordpress": "0.0.0",
88
- "@ainyc/canonry-provider-perplexity": "0.0.0"
88
+ "@ainyc/canonry-provider-gemini": "0.0.0"
89
89
  },
90
90
  "scripts": {
91
91
  "build": "tsx scripts/copy-agent-assets.ts && tsup && tsx build-web.ts",