@canonry/canonry 6.3.1 → 7.1.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 (44) hide show
  1. package/README.md +3 -3
  2. package/assets/agent-workspace/skills/aero/SKILL.md +2 -2
  3. package/assets/agent-workspace/skills/aero/references/reporting.md +26 -23
  4. package/assets/agent-workspace/skills/canonry/references/canonry-cli.md +55 -22
  5. package/assets/agent-workspace/skills/canonry/references/server-side-traffic.md +17 -6
  6. package/assets/assets/AuditHistoryPanel-CZWzgyrD.js +1 -0
  7. package/assets/assets/{BacklinksPage-aBcxpN_9.js → BacklinksPage-D23A-ahd.js} +1 -1
  8. package/assets/assets/ChartPrimitives-CYlrwLJs.js +1 -0
  9. package/assets/assets/{HistoryPage-PoBuxiY_.js → HistoryPage-BKGVxmNz.js} +1 -1
  10. package/assets/assets/MeasurementPropertyPage-BSxn6_RB.js +1 -0
  11. package/assets/assets/ProjectPage-D9W8G_1m.js +8 -0
  12. package/assets/assets/{RunsPage-CHHxOpzo.js → RunsPage-CeBBjLSE.js} +1 -1
  13. package/assets/assets/{SettingsPage-CNKnrLXC.js → SettingsPage-Jp5Yp4cz.js} +1 -1
  14. package/assets/assets/SiteHealthSection-DzVegBeN.js +4 -0
  15. package/assets/assets/{TrafficPage-CY-ibXnb.js → TrafficPage-B66AYwWk.js} +2 -2
  16. package/assets/assets/{TrafficSourceDetailPage-BgiPXubs.js → TrafficSourceDetailPage-CXtq1yES.js} +1 -1
  17. package/assets/assets/{extract-error-message-H1dzzfBP.js → extract-error-message-BVa0lOze.js} +1 -1
  18. package/assets/assets/index-CMe_-fAB.css +1 -0
  19. package/assets/assets/index-DuhS0WLM.js +86 -0
  20. package/assets/assets/{react-sigma_core.esm.min-uiYtR_DU.js → react-sigma_core.esm.min-60drsJa6.js} +1 -1
  21. package/assets/assets/v2-overview-adapter-CLUi2Lkv.js +1 -0
  22. package/assets/assets/{vendor-recharts-llkUFBGR.js → vendor-recharts-D-cUuLZo.js} +1 -1
  23. package/assets/index.html +3 -3
  24. package/dist/{chunk-4WZUR7XX.js → chunk-22R5E5CY.js} +101 -192
  25. package/dist/{chunk-DERWXLHX.js → chunk-2OQ6D26U.js} +66 -20
  26. package/dist/{chunk-5GY5WBAF.js → chunk-IAMECH2N.js} +3 -3
  27. package/dist/{chunk-ZZEPF3A5.js → chunk-MTSFSXCG.js} +83 -19
  28. package/dist/{chunk-5FYTFE5T.js → chunk-U2S5ABOR.js} +2 -2
  29. package/dist/{chunk-7CVTTQRV.js → chunk-VDX3LYKL.js} +4460 -8332
  30. package/dist/{chunk-EV5G5QRR.js → chunk-YGHPT5B2.js} +1475 -3002
  31. package/dist/cli.js +240 -178
  32. package/dist/{demo-server-AIFR77TP.js → demo-server-TIMYQLXS.js} +5 -14
  33. package/dist/index.js +6 -6
  34. package/dist/{intelligence-service-SYISPW25.js → intelligence-service-YCMRTVCI.js} +2 -2
  35. package/dist/mcp.js +4 -4
  36. package/package.json +15 -15
  37. package/assets/assets/AuditHistoryPanel-BUYWIjlG.js +0 -1
  38. package/assets/assets/ChartPrimitives-B5okB5g-.js +0 -1
  39. package/assets/assets/MeasurementPropertyPage-DyjyqHac.js +0 -1
  40. package/assets/assets/ProjectPage-Mmv5YW-K.js +0 -8
  41. package/assets/assets/SiteHealthSection-C9RivT7G.js +0 -4
  42. package/assets/assets/index-C17E5ZcA.css +0 -1
  43. package/assets/assets/index-DSCun3I9.js +0 -86
  44. package/assets/assets/v2-overview-adapter-BQokN2eb.js +0 -1
package/dist/cli.js CHANGED
@@ -35,11 +35,11 @@ import {
35
35
  trackCliCommandFinished,
36
36
  trackEvent,
37
37
  waitForServerRuntimeStartup
38
- } from "./chunk-4WZUR7XX.js";
38
+ } from "./chunk-22R5E5CY.js";
39
39
  import {
40
40
  autoSyncSkills,
41
41
  formatAutoSyncNotice
42
- } from "./chunk-5GY5WBAF.js";
42
+ } from "./chunk-IAMECH2N.js";
43
43
  import {
44
44
  configExists,
45
45
  createApiClient,
@@ -56,13 +56,13 @@ import {
56
56
  saveConfig,
57
57
  saveConfigPatch,
58
58
  shouldPrintServeSkillsNudge
59
- } from "./chunk-ZZEPF3A5.js";
59
+ } from "./chunk-MTSFSXCG.js";
60
60
  import {
61
61
  DEFAULT_DEMO_TRUSTED_PROXIES,
62
62
  trustedProxiesProblem,
63
63
  trustedProxyProblem
64
64
  } from "./chunk-RB2F4D3Z.js";
65
- import "./chunk-5FYTFE5T.js";
65
+ import "./chunk-U2S5ABOR.js";
66
66
  import {
67
67
  CliError,
68
68
  EXIT_SYSTEM_ERROR,
@@ -74,7 +74,7 @@ import {
74
74
  runMeasurementDraftAction,
75
75
  systemError,
76
76
  usageError
77
- } from "./chunk-DERWXLHX.js";
77
+ } from "./chunk-2OQ6D26U.js";
78
78
  import {
79
79
  CLOUDFLARE_WORKER_BINDINGS,
80
80
  CLOUDFLARE_WORKER_GENERATED_MARKER,
@@ -88,9 +88,8 @@ import {
88
88
  migrate,
89
89
  projects,
90
90
  queries,
91
- renderReportHtml,
92
91
  runs
93
- } from "./chunk-7CVTTQRV.js";
92
+ } from "./chunk-VDX3LYKL.js";
94
93
  import {
95
94
  AdsDeliverySnapshotStatuses,
96
95
  AdsHistoricalCampaignRollupStatuses,
@@ -109,7 +108,6 @@ import {
109
108
  OUTSTANDING_PROVIDER_BATCH_STATUSES,
110
109
  ProviderBatchStatuses,
111
110
  READ_ONLY_SCOPE,
112
- REPORT_PERIOD_OPTIONS,
113
111
  RatioUnits,
114
112
  ResearchRunStatuses,
115
113
  RunKinds,
@@ -139,6 +137,7 @@ import {
139
137
  buildModelChangeNotice,
140
138
  canonicalizeGtmAccountId,
141
139
  canonicalizeGtmResourceSelection,
140
+ contentTargetDismissRequestSchema,
142
141
  conversionTrackingContractWriteRequestSchema,
143
142
  deduplicateResearchQueries,
144
143
  describeError,
@@ -176,12 +175,12 @@ import {
176
175
  normalizeProjectAliases,
177
176
  normalizeTelemetryStatus,
178
177
  notificationEventSchema,
178
+ parseTrafficAnalyticsPeriod,
179
179
  providerDispatchModeSchema,
180
180
  queryClassFilterSchema,
181
181
  queryTrackingCommitRequestSchema,
182
182
  queryTrackingPreviewRequestSchema,
183
183
  referralAssessmentQuerySchema,
184
- reportUnattributedAnswers,
185
184
  researchBatchCreateSchema,
186
185
  resolveNegativeReviewMaxStars,
187
186
  resolveProjectQualifiedAliases,
@@ -197,10 +196,11 @@ import {
197
196
  shareOfVoiceLabel,
198
197
  shareOfVoiceReason,
199
198
  snapshotProviderModeSchema,
199
+ unattributedAnswersLabel,
200
200
  visibilityCompareSelectionSchema,
201
201
  visibilityReportRequestSchema,
202
202
  winnabilityClassSchema
203
- } from "./chunk-EV5G5QRR.js";
203
+ } from "./chunk-YGHPT5B2.js";
204
204
 
205
205
  // src/cli.ts
206
206
  import { pathToFileURL } from "url";
@@ -253,9 +253,9 @@ Usage: ${spec.usage}
253
253
  if (spec.help) console.log(`${spec.help}
254
254
  `);
255
255
  }
256
- function matchesPath(args, path13) {
257
- if (args.length < path13.length) return false;
258
- return path13.every((segment, index) => args[index] === segment);
256
+ function matchesPath(args, path12) {
257
+ if (args.length < path12.length) return false;
258
+ return path12.every((segment, index) => args[index] === segment);
259
259
  }
260
260
  function withGlobalOptions(options) {
261
261
  const base = options ? { ...options } : {};
@@ -734,7 +734,7 @@ function parseDemoTrustedProxies(values) {
734
734
  async function demoCommand(options) {
735
735
  const { host, port } = parseDemoListenOptions(options);
736
736
  const trustProxy = parseDemoTrustedProxies(options.trustProxy);
737
- const { createDemoServer } = await import("./demo-server-AIFR77TP.js");
737
+ const { createDemoServer } = await import("./demo-server-TIMYQLXS.js");
738
738
  const app = await createDemoServer({ trustProxy });
739
739
  let stopping = false;
740
740
  const stop = () => {
@@ -4369,9 +4369,9 @@ async function gaConnect(project2, opts) {
4369
4369
  propertyId: opts.propertyId
4370
4370
  };
4371
4371
  if (opts.keyFile) {
4372
- const fs20 = await import("fs");
4372
+ const fs19 = await import("fs");
4373
4373
  try {
4374
- const content = fs20.readFileSync(opts.keyFile, "utf-8");
4374
+ const content = fs19.readFileSync(opts.keyFile, "utf-8");
4375
4375
  JSON.parse(content);
4376
4376
  body.keyJson = content;
4377
4377
  } catch (e) {
@@ -6500,9 +6500,9 @@ async function getCommand(opts) {
6500
6500
  console.log(JSON.stringify(leaf, null, 2));
6501
6501
  }
6502
6502
  }
6503
- function walkPath(value, path13) {
6504
- if (!path13 || path13 === ".") return value;
6505
- const segments = path13.split(".").flatMap((part) => {
6503
+ function walkPath(value, path12) {
6504
+ if (!path12 || path12 === ".") return value;
6505
+ const segments = path12.split(".").flatMap((part) => {
6506
6506
  const tokens = [];
6507
6507
  let i = 0;
6508
6508
  const bracketStart = part.indexOf("[");
@@ -6550,13 +6550,13 @@ var GET_CLI_COMMANDS = [
6550
6550
  },
6551
6551
  run: async (input) => {
6552
6552
  const project2 = requireProject(input, "get", USAGE2);
6553
- const path13 = requirePositional(input, 1, {
6553
+ const path12 = requirePositional(input, 1, {
6554
6554
  command: "get",
6555
6555
  usage: USAGE2,
6556
6556
  message: 'path is required (e.g. "scores.mentionShare.value")'
6557
6557
  });
6558
6558
  const from = getString(input.values, "from");
6559
- await getCommand({ project: project2, path: path13, from, format: input.format });
6559
+ await getCommand({ project: project2, path: path12, from, format: input.format });
6560
6560
  }
6561
6561
  }
6562
6562
  ];
@@ -7225,9 +7225,9 @@ async function trafficConnectWordpress(project2, opts) {
7225
7225
  }
7226
7226
  let applicationPassword = opts.appPassword?.trim() ?? "";
7227
7227
  if (!applicationPassword && opts.appPasswordFile) {
7228
- const fs20 = await import("fs");
7228
+ const fs19 = await import("fs");
7229
7229
  try {
7230
- applicationPassword = fs20.readFileSync(opts.appPasswordFile, "utf-8").trim();
7230
+ applicationPassword = fs19.readFileSync(opts.appPasswordFile, "utf-8").trim();
7231
7231
  } catch (e) {
7232
7232
  const msg = describeError(e);
7233
7233
  throw new CliError({
@@ -7283,10 +7283,10 @@ async function trafficConnectCloudRun(project2, opts) {
7283
7283
  details: { project: project2 }
7284
7284
  });
7285
7285
  }
7286
- const fs20 = await import("fs");
7286
+ const fs19 = await import("fs");
7287
7287
  let keyJson;
7288
7288
  try {
7289
- keyJson = fs20.readFileSync(opts.serviceAccountKey, "utf-8");
7289
+ keyJson = fs19.readFileSync(opts.serviceAccountKey, "utf-8");
7290
7290
  JSON.parse(keyJson);
7291
7291
  } catch (e) {
7292
7292
  const msg = describeError(e);
@@ -7346,9 +7346,9 @@ async function trafficConnectVercel(project2, opts) {
7346
7346
  }
7347
7347
  let token = opts.token?.trim() ?? "";
7348
7348
  if (!token && opts.tokenFile) {
7349
- const fs20 = await import("fs");
7349
+ const fs19 = await import("fs");
7350
7350
  try {
7351
- token = fs20.readFileSync(opts.tokenFile, "utf-8").trim();
7351
+ token = fs19.readFileSync(opts.tokenFile, "utf-8").trim();
7352
7352
  } catch (e) {
7353
7353
  const msg = describeError(e);
7354
7354
  throw new CliError({
@@ -7560,6 +7560,51 @@ async function trafficSources(project2, opts) {
7560
7560
  console.log(` ${formatSourceLine(source)}`);
7561
7561
  }
7562
7562
  }
7563
+ async function trafficAnalytics(project2, opts) {
7564
+ let period;
7565
+ try {
7566
+ period = parseTrafficAnalyticsPeriod(opts.period);
7567
+ } catch (error) {
7568
+ throw usageError(`Error: ${describeError(error)}
7569
+
7570
+ Usage: canonry traffic analytics <project> [--period 7|14|30|90] [--format json]`);
7571
+ }
7572
+ const result = await createApiClient().getTrafficAnalytics(project2, period);
7573
+ if (isMachineFormat(opts.format)) {
7574
+ console.log(JSON.stringify(result, null, 2));
7575
+ return;
7576
+ }
7577
+ const activity = result.activity;
7578
+ if (!activity) {
7579
+ console.log(`No traffic sources connected for project "${project2}".`);
7580
+ return;
7581
+ }
7582
+ console.log(`Traffic analytics for "${project2}": ${activity.windowStart} to ${activity.windowEnd}`);
7583
+ console.log(` First stored observation: ${activity.coverageStart ?? "none"}`);
7584
+ if (!activity.priorWindowComplete) console.log(" Prior recording window is incomplete; percentage changes are unavailable.");
7585
+ for (const [label, counts] of [
7586
+ ["Verified crawler hits", activity.verifiedCrawlerHits],
7587
+ ["Unverified crawler hits", activity.unverifiedCrawlerHits],
7588
+ ["AI user-fetch hits", activity.aiUserFetchHits],
7589
+ ["AI-referral arrivals", activity.referralArrivals],
7590
+ ["Paid AI-referral arrivals", activity.referralArrivalsByClass.paid],
7591
+ ["Organic AI-referral arrivals", activity.referralArrivalsByClass.organic],
7592
+ ["Unclassified AI-referral arrivals", activity.referralArrivalsByClass.unclassified]
7593
+ ]) {
7594
+ console.log(` ${label}: ${counts.current} (prior ${counts.prior}; change ${counts.deltaPct === null ? "unavailable" : formatPercent(counts.deltaPct, "percent")})`);
7595
+ }
7596
+ console.log(` AI-referral redirect hops: ${activity.referralRedirects}`);
7597
+ console.log("Operators: OPERATOR VERIFIED UNVERIFIED USER_FETCH REFERRALS CHANGE");
7598
+ for (const row of activity.byOperator) console.log(` ${row.operator} ${row.verifiedHits} ${row.unverifiedHits} ${row.userFetchHits} ${row.referralArrivals} ${row.deltaPct === null ? "unavailable" : formatPercent(row.deltaPct, "percent")}`);
7599
+ console.log("Crawled paths: PATH VERIFIED UNVERIFIED OPERATORS");
7600
+ for (const row of activity.topCrawledPaths) console.log(` ${row.path} ${row.verifiedHits} ${row.unverifiedHits} ${row.distinctOperators}`);
7601
+ console.log("AI-referral products: PRODUCT ARRIVALS LANDING_PATHS");
7602
+ for (const row of activity.referralProducts) console.log(` ${row.product} ${row.arrivals} ${row.distinctLandingPaths}`);
7603
+ console.log("Daily history: DATE VERIFIED UNVERIFIED USER_FETCH REFERRALS");
7604
+ for (const row of activity.dailyTrend) console.log(` ${row.date} ${row.verifiedCrawlerHits} ${row.unverifiedCrawlerHits} ${row.userFetchHits} ${row.referralArrivals}`);
7605
+ console.log("AI-referral landing paths: PATH ARRIVALS PRODUCTS");
7606
+ for (const row of activity.topReferralLandingPaths) console.log(` ${row.path} ${row.arrivals} ${row.distinctProducts}`);
7607
+ }
7563
7608
  async function trafficStatus(project2, opts) {
7564
7609
  const client = createApiClient();
7565
7610
  const result = await client.trafficStatus(project2);
@@ -7732,6 +7777,16 @@ async function trafficReferralAssessment(project2, options) {
7732
7777
 
7733
7778
  // src/cli-commands/traffic.ts
7734
7779
  var TRAFFIC_CLI_COMMANDS = [
7780
+ {
7781
+ path: ["traffic", "analytics"],
7782
+ usage: "canonry traffic analytics <project> [--period 7|14|30|90] [--format json]",
7783
+ help: "Complete stored traffic totals and breakdowns for the selected window. Project-wide for Simple and Advanced portfolios; no provider calls or sync.",
7784
+ options: { period: stringOption() },
7785
+ run: async (input) => {
7786
+ const project2 = requireProject(input, "traffic.analytics", "canonry traffic analytics <project> [--period 7|14|30|90]");
7787
+ await trafficAnalytics(project2, { period: getString(input.values, "period"), format: input.format });
7788
+ }
7789
+ },
7735
7790
  {
7736
7791
  path: ["traffic", "referral-assessment"],
7737
7792
  usage: "canonry traffic referral-assessment <project> --start-date YYYY-MM-DD --end-date YYYY-MM-DD [--source <id>] [--burst-threshold 100] [--ratio-threshold 3] [--limit 100] [--format json]",
@@ -8068,7 +8123,7 @@ var TRAFFIC_CLI_COMMANDS = [
8068
8123
  unknownSubcommand(input.positionals[0], {
8069
8124
  command: "traffic",
8070
8125
  usage: "canonry traffic <subcommand> <project> [args]",
8071
- available: ["connect", "activate", "sync", "backfill", "status", "sources", "events"]
8126
+ available: ["connect", "activate", "sync", "backfill", "reset", "status", "sources", "events", "analytics", "referral-assessment"]
8072
8127
  });
8073
8128
  }
8074
8129
  }
@@ -10858,7 +10913,7 @@ var METRIC_REASONS = {
10858
10913
  not_applicable: "not measured (not applicable)"
10859
10914
  };
10860
10915
  function unattributedText(metric) {
10861
- return metric.state === "available" ? reportUnattributedAnswers(metric) : null;
10916
+ return metric.state === "available" ? unattributedAnswersLabel(metric) : null;
10862
10917
  }
10863
10918
  function metricText(metric) {
10864
10919
  if (metric.state === "unavailable") return METRIC_REASONS[metric.reason] ?? `not measured (${metric.reason})`;
@@ -12977,71 +13032,6 @@ function parseNegativeReviewMaxStars(raw) {
12977
13032
  return parsed.data;
12978
13033
  }
12979
13034
 
12980
- // src/commands/report.ts
12981
- import fs13 from "fs";
12982
- import path6 from "path";
12983
- function defaultOutputPath(project2, audience) {
12984
- const date = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
12985
- return path6.resolve(process.cwd(), `canonry-report-${project2}-${audience}-${date}.html`);
12986
- }
12987
- async function runReportCommand(project2, opts = {}) {
12988
- const client = createApiClient();
12989
- const report = await client.getReport(project2, opts.period !== void 0 ? { period: opts.period } : void 0);
12990
- const audience = opts.audience ?? "agency";
12991
- if (isMachineFormat(opts.format)) {
12992
- console.log(JSON.stringify(report, null, 2));
12993
- return;
12994
- }
12995
- const html = renderReportHtml(report, { audience });
12996
- const targetPath = opts.output ? path6.resolve(opts.output) : defaultOutputPath(project2, audience);
12997
- const dir = path6.dirname(targetPath);
12998
- if (!fs13.existsSync(dir)) {
12999
- fs13.mkdirSync(dir, { recursive: true });
13000
- }
13001
- fs13.writeFileSync(targetPath, html, "utf-8");
13002
- console.log(`Report written to ${targetPath}`);
13003
- }
13004
-
13005
- // src/cli-commands/report.ts
13006
- var USAGE3 = "canonry report <project> [--audience agency|client] [--period 7|14|30|90] [--output <path>] [--format json]";
13007
- function parseAudience(value) {
13008
- if (value === void 0) return void 0;
13009
- if (value === "agency" || value === "client") return value;
13010
- throw usageError(`Error: --audience must be "agency" or "client"
13011
-
13012
- Usage: ${USAGE3}`);
13013
- }
13014
- function parsePeriod(value) {
13015
- if (value === void 0) return void 0;
13016
- const n = Number(value);
13017
- if (Number.isInteger(n) && REPORT_PERIOD_OPTIONS.includes(n)) {
13018
- return n;
13019
- }
13020
- throw usageError(`Error: --period must be one of ${REPORT_PERIOD_OPTIONS.join(", ")}
13021
-
13022
- Usage: ${USAGE3}`);
13023
- }
13024
- var REPORT_CLI_COMMANDS = [
13025
- {
13026
- path: ["report"],
13027
- usage: USAGE3,
13028
- options: {
13029
- audience: { type: "string" },
13030
- period: { type: "string" },
13031
- output: { type: "string", short: "o" }
13032
- },
13033
- run: async (input) => {
13034
- const project2 = requireProject(input, "report", USAGE3);
13035
- await runReportCommand(project2, {
13036
- format: input.format,
13037
- audience: parseAudience(getString(input.values, "audience")),
13038
- period: parsePeriod(getString(input.values, "period")),
13039
- output: getString(input.values, "output")
13040
- });
13041
- }
13042
- }
13043
- ];
13044
-
13045
13035
  // src/commands/organic-evidence.ts
13046
13036
  async function showOrganicEvidence(project2, opts) {
13047
13037
  const data = await createApiClient().getOrganicEvidence(project2, opts.period);
@@ -13083,23 +13073,23 @@ function printOrganicEvidence(project2, data) {
13083
13073
  }
13084
13074
 
13085
13075
  // src/cli-commands/organic-evidence.ts
13086
- var USAGE4 = "canonry organic-evidence <project> [--period 60|90] [--format json|jsonl]";
13087
- function parsePeriod2(value) {
13076
+ var USAGE3 = "canonry organic-evidence <project> [--period 60|90] [--format json|jsonl]";
13077
+ function parsePeriod(value) {
13088
13078
  if (value === void 0) return void 0;
13089
13079
  if (value === "60" || value === "90") return Number(value);
13090
13080
  throw usageError(`Error: --period must be 60 or 90
13091
13081
 
13092
- Usage: ${USAGE4}`);
13082
+ Usage: ${USAGE3}`);
13093
13083
  }
13094
13084
  var ORGANIC_EVIDENCE_CLI_COMMANDS = [
13095
13085
  {
13096
13086
  path: ["organic-evidence"],
13097
- usage: USAGE4,
13087
+ usage: USAGE3,
13098
13088
  options: { period: stringOption() },
13099
13089
  run: async (input) => {
13100
- const project2 = requireProject(input, "organic-evidence", USAGE4);
13090
+ const project2 = requireProject(input, "organic-evidence", USAGE3);
13101
13091
  await showOrganicEvidence(project2, {
13102
- period: parsePeriod2(getString(input.values, "period")),
13092
+ period: parsePeriod(getString(input.values, "period")),
13103
13093
  format: input.format
13104
13094
  });
13105
13095
  }
@@ -14354,12 +14344,12 @@ var SKILLS_CLI_COMMANDS = [
14354
14344
  ];
14355
14345
 
14356
14346
  // src/commands/snapshot.ts
14357
- import fs15 from "fs";
14358
- import path8 from "path";
14359
-
14360
- // src/snapshot-pdf.ts
14361
14347
  import fs14 from "fs";
14362
14348
  import path7 from "path";
14349
+
14350
+ // src/snapshot-pdf.ts
14351
+ import fs13 from "fs";
14352
+ import path6 from "path";
14363
14353
  import { PDFDocument, StandardFonts, rgb } from "pdf-lib";
14364
14354
  var PAGE_WIDTH = 612;
14365
14355
  var PAGE_HEIGHT = 792;
@@ -14571,9 +14561,9 @@ async function writeSnapshotPdf(report, outputPath) {
14571
14561
  renderCompetitors(pdf, report);
14572
14562
  renderQueries(pdf, report);
14573
14563
  const bytes = await doc.save();
14574
- const resolvedPath = path7.resolve(outputPath);
14575
- fs14.mkdirSync(path7.dirname(resolvedPath), { recursive: true });
14576
- fs14.writeFileSync(resolvedPath, bytes);
14564
+ const resolvedPath = path6.resolve(outputPath);
14565
+ fs13.mkdirSync(path6.dirname(resolvedPath), { recursive: true });
14566
+ fs13.writeFileSync(resolvedPath, bytes);
14577
14567
  return resolvedPath;
14578
14568
  }
14579
14569
  function renderCover(pdf, report) {
@@ -14733,9 +14723,9 @@ Markdown saved: ${savedMdPath}`);
14733
14723
  PDF saved: ${savedPdfPath}`);
14734
14724
  }
14735
14725
  function writeSnapshotMarkdown(report, outputPath) {
14736
- const resolvedPath = path8.resolve(outputPath);
14737
- fs15.mkdirSync(path8.dirname(resolvedPath), { recursive: true });
14738
- fs15.writeFileSync(resolvedPath, formatSnapshotMarkdown(report), "utf-8");
14726
+ const resolvedPath = path7.resolve(outputPath);
14727
+ fs14.mkdirSync(path7.dirname(resolvedPath), { recursive: true });
14728
+ fs14.writeFileSync(resolvedPath, formatSnapshotMarkdown(report), "utf-8");
14739
14729
  return resolvedPath;
14740
14730
  }
14741
14731
  function formatSnapshotMarkdown(report) {
@@ -15447,6 +15437,44 @@ var INTELLIGENCE_CLI_COMMANDS = [
15447
15437
 
15448
15438
  // src/commands/content.ts
15449
15439
  var WINNABILITY_COVERAGE_CHECK_ID = "content.winnability.coverage";
15440
+ async function listContentDismissals(project2, opts) {
15441
+ const response = await createApiClient().getContentDismissals(project2);
15442
+ if (opts.format === "jsonl") {
15443
+ emitJsonl(response.dismissals.map((row) => ({ project: project2, ...row })));
15444
+ return;
15445
+ }
15446
+ if (isMachineFormat(opts.format)) {
15447
+ console.log(JSON.stringify(response, null, 2));
15448
+ return;
15449
+ }
15450
+ if (response.dismissals.length === 0) {
15451
+ console.log("No addressed content targets.");
15452
+ return;
15453
+ }
15454
+ for (const row of response.dismissals) {
15455
+ console.log(`${row.targetRef} \xB7 ${row.dismissedAt}`);
15456
+ if (row.addressedUrl) console.log(` Addressed URL: ${row.addressedUrl}`);
15457
+ if (row.note) console.log(` Note: ${row.note}`);
15458
+ }
15459
+ }
15460
+ async function dismissContentTarget(project2, request, opts) {
15461
+ const parsed = contentTargetDismissRequestSchema.safeParse(request);
15462
+ if (!parsed.success) throw usageError(parsed.error.issues[0]?.message ?? "Invalid content dismissal.");
15463
+ const response = await createApiClient().dismissContentTarget(project2, parsed.data);
15464
+ if (isMachineFormat(opts.format)) {
15465
+ console.log(JSON.stringify(response, null, 2));
15466
+ return;
15467
+ }
15468
+ console.log(`Marked ${response.targetRef} addressed. Restore with canonry content restore ${project2} ${response.targetRef}.`);
15469
+ }
15470
+ async function restoreContentTarget(project2, targetRef, opts) {
15471
+ await createApiClient().restoreContentTarget(project2, targetRef);
15472
+ if (isMachineFormat(opts.format)) {
15473
+ console.log(JSON.stringify({ targetRef, restored: true }, null, 2));
15474
+ return;
15475
+ }
15476
+ console.log(`Restored ${targetRef}. It can appear in content targets when still eligible.`);
15477
+ }
15450
15478
  async function listContentTargets(project2, opts) {
15451
15479
  const client = createApiClient();
15452
15480
  const response = await client.getContentTargets(project2, {
@@ -15483,6 +15511,7 @@ async function listContentTargets(project2, opts) {
15483
15511
  const conf = target.actionConfidence.padEnd(6);
15484
15512
  const surface = target.winnabilityClass === "ceded" ? "CEDED " : "ownable";
15485
15513
  console.log(`${action} ${score} conf=${conf} [${surface}] ${target.query}`);
15514
+ console.log(` target ref: ${target.targetRef}`);
15486
15515
  if (target.ourBestPage) {
15487
15516
  const posLabel = target.ourBestPage.gscAvgPosition !== null ? `pos #${target.ourBestPage.gscAvgPosition}` : "no GSC ranking";
15488
15517
  console.log(` our page: ${target.ourBestPage.url} (${posLabel})`);
@@ -15637,6 +15666,40 @@ async function warnIfWinnabilityCoverageIsLow(client, project2, format) {
15637
15666
 
15638
15667
  // src/cli-commands/content.ts
15639
15668
  var CONTENT_CLI_COMMANDS = [
15669
+ {
15670
+ path: ["content", "dismissals"],
15671
+ usage: "canonry content dismissals <project> [--format json|jsonl]",
15672
+ help: "List persisted addressed content targets, including those hidden from content targets.",
15673
+ options: {},
15674
+ run: async (input) => {
15675
+ const project2 = requireProject(input, "content dismissals", "canonry content dismissals <project> [--format json|jsonl]");
15676
+ await listContentDismissals(project2, { format: input.format });
15677
+ }
15678
+ },
15679
+ {
15680
+ path: ["content", "dismiss"],
15681
+ usage: "canonry content dismiss <project> <targetRef> [--addressed-url <url>] [--note <text>] [--format json]",
15682
+ help: "Mark a content target addressed. Restore it with content restore.",
15683
+ options: { "addressed-url": { type: "string" }, note: { type: "string" } },
15684
+ run: async (input) => {
15685
+ const usage = "canonry content dismiss <project> <targetRef> [--addressed-url <url>] [--note <text>] [--format json]";
15686
+ const project2 = requireProject(input, "content dismiss", usage);
15687
+ const targetRef = requirePositional(input, 1, { command: "content dismiss", usage, message: "targetRef is required (from content targets)" });
15688
+ await dismissContentTarget(project2, { targetRef, addressedUrl: getString(input.values, "addressed-url"), note: getString(input.values, "note") }, { format: input.format });
15689
+ }
15690
+ },
15691
+ {
15692
+ path: ["content", "restore"],
15693
+ usage: "canonry content restore <project> <targetRef> [--format json]",
15694
+ help: "Remove a persisted dismissal so an eligible target can appear again.",
15695
+ options: {},
15696
+ run: async (input) => {
15697
+ const usage = "canonry content restore <project> <targetRef> [--format json]";
15698
+ const project2 = requireProject(input, "content restore", usage);
15699
+ const targetRef = requirePositional(input, 1, { command: "content restore", usage, message: "targetRef is required (from content dismissals)" });
15700
+ await restoreContentTarget(project2, targetRef, { format: input.format });
15701
+ }
15702
+ },
15640
15703
  {
15641
15704
  path: ["content", "targets"],
15642
15705
  usage: "canonry content targets <project> [--limit <n>] [--include-in-progress] [--ownable] [--winnability-class <ownable|ceded>] [--format json]",
@@ -15730,7 +15793,7 @@ var CONTENT_CLI_COMMANDS = [
15730
15793
 
15731
15794
  // src/commands/bootstrap.ts
15732
15795
  import crypto2 from "crypto";
15733
- import path9 from "path";
15796
+ import path8 from "path";
15734
15797
  import { isDeepStrictEqual } from "util";
15735
15798
  import { eq } from "drizzle-orm";
15736
15799
  function persistedValue(value) {
@@ -15750,7 +15813,7 @@ async function bootstrapCommand(opts) {
15750
15813
  const existing = configExists();
15751
15814
  const existingConfig = existing ? loadConfig() : void 0;
15752
15815
  const existingRaw = existing ? loadConfigRaw() : null;
15753
- const databasePath = env.databasePath || existingRaw?.database || path9.join(configDir, "data.db");
15816
+ const databasePath = env.databasePath || existingRaw?.database || path8.join(configDir, "data.db");
15754
15817
  let rawApiKey;
15755
15818
  let generatedApiKey;
15756
15819
  if (env.apiKey) {
@@ -15866,8 +15929,8 @@ async function bootstrapCommand(opts) {
15866
15929
 
15867
15930
  // src/commands/daemon.ts
15868
15931
  import { spawn as spawn2 } from "child_process";
15869
- import fs16 from "fs";
15870
- import path10 from "path";
15932
+ import fs15 from "fs";
15933
+ import path9 from "path";
15871
15934
 
15872
15935
  // src/operator-url.ts
15873
15936
  function operatorHost(bindHost) {
@@ -15890,7 +15953,7 @@ function resolveServePort(envPort, configPort) {
15890
15953
 
15891
15954
  // src/commands/daemon.ts
15892
15955
  function getPidPath() {
15893
- return path10.join(getConfigDir(), "canonry.pid");
15956
+ return path9.join(getConfigDir(), "canonry.pid");
15894
15957
  }
15895
15958
  function isProcessAlive(pid) {
15896
15959
  try {
@@ -15937,8 +16000,8 @@ function buildServeForwardArgs(opts) {
15937
16000
  async function startDaemon(opts) {
15938
16001
  const pidPath = getPidPath();
15939
16002
  const format = opts.format ?? "text";
15940
- if (fs16.existsSync(pidPath)) {
15941
- const existingPid = parseInt(fs16.readFileSync(pidPath, "utf-8").trim(), 10);
16003
+ if (fs15.existsSync(pidPath)) {
16004
+ const existingPid = parseInt(fs15.readFileSync(pidPath, "utf-8").trim(), 10);
15942
16005
  if (!isNaN(existingPid) && isProcessAlive(existingPid)) {
15943
16006
  throw new CliError({
15944
16007
  code: "DAEMON_ALREADY_RUNNING",
@@ -15949,13 +16012,13 @@ async function startDaemon(opts) {
15949
16012
  }
15950
16013
  });
15951
16014
  }
15952
- fs16.unlinkSync(pidPath);
16015
+ fs15.unlinkSync(pidPath);
15953
16016
  }
15954
16017
  const config = loadConfig();
15955
16018
  const endpoint = resolveDaemonEndpoint(opts, process.env, config.port);
15956
16019
  const host = endpoint.host;
15957
16020
  const port = String(endpoint.port);
15958
- const cliPath = path10.resolve(new URL(import.meta.url).pathname);
16021
+ const cliPath = path9.resolve(new URL(import.meta.url).pathname);
15959
16022
  const inSourceMode = new URL(import.meta.url).pathname.endsWith(".ts");
15960
16023
  const args = inSourceMode ? ["--import", "tsx", cliPath, "serve"] : [cliPath, "serve"];
15961
16024
  args.push(...buildServeForwardArgs({ ...opts, host, port }));
@@ -15972,10 +16035,10 @@ async function startDaemon(opts) {
15972
16035
  });
15973
16036
  }
15974
16037
  const configDir = getConfigDir();
15975
- if (!fs16.existsSync(configDir)) {
15976
- fs16.mkdirSync(configDir, { recursive: true });
16038
+ if (!fs15.existsSync(configDir)) {
16039
+ fs15.mkdirSync(configDir, { recursive: true });
15977
16040
  }
15978
- fs16.writeFileSync(pidPath, String(child.pid), "utf-8");
16041
+ fs15.writeFileSync(pidPath, String(child.pid), "utf-8");
15979
16042
  if (!isMachineFormat(format)) {
15980
16043
  process.stderr.write("Waiting for server to start...");
15981
16044
  }
@@ -15986,7 +16049,7 @@ async function startDaemon(opts) {
15986
16049
  } catch {
15987
16050
  }
15988
16051
  try {
15989
- fs16.unlinkSync(pidPath);
16052
+ fs15.unlinkSync(pidPath);
15990
16053
  } catch {
15991
16054
  }
15992
16055
  throw new CliError({
@@ -16018,7 +16081,7 @@ async function startDaemon(opts) {
16018
16081
  }
16019
16082
  function stopDaemon(format = "text") {
16020
16083
  const pidPath = getPidPath();
16021
- if (!fs16.existsSync(pidPath)) {
16084
+ if (!fs15.existsSync(pidPath)) {
16022
16085
  if (isMachineFormat(format)) {
16023
16086
  console.log(JSON.stringify({
16024
16087
  stopped: false,
@@ -16029,7 +16092,7 @@ function stopDaemon(format = "text") {
16029
16092
  console.log("Canonry is not running (no PID file found)");
16030
16093
  return;
16031
16094
  }
16032
- const pid = parseInt(fs16.readFileSync(pidPath, "utf-8").trim(), 10);
16095
+ const pid = parseInt(fs15.readFileSync(pidPath, "utf-8").trim(), 10);
16033
16096
  if (isNaN(pid)) {
16034
16097
  if (isMachineFormat(format)) {
16035
16098
  console.log(JSON.stringify({
@@ -16040,7 +16103,7 @@ function stopDaemon(format = "text") {
16040
16103
  } else {
16041
16104
  console.error("Invalid PID file. Removing it.");
16042
16105
  }
16043
- fs16.unlinkSync(pidPath);
16106
+ fs15.unlinkSync(pidPath);
16044
16107
  return;
16045
16108
  }
16046
16109
  if (!isProcessAlive(pid)) {
@@ -16054,12 +16117,12 @@ function stopDaemon(format = "text") {
16054
16117
  } else {
16055
16118
  console.log(`Canonry is not running (stale PID: ${pid}). Cleaning up.`);
16056
16119
  }
16057
- fs16.unlinkSync(pidPath);
16120
+ fs15.unlinkSync(pidPath);
16058
16121
  return;
16059
16122
  }
16060
16123
  try {
16061
16124
  process.kill(pid, "SIGTERM");
16062
- fs16.unlinkSync(pidPath);
16125
+ fs15.unlinkSync(pidPath);
16063
16126
  if (isMachineFormat(format)) {
16064
16127
  console.log(JSON.stringify({
16065
16128
  stopped: true,
@@ -16083,9 +16146,9 @@ function stopDaemon(format = "text") {
16083
16146
 
16084
16147
  // src/commands/init.ts
16085
16148
  import crypto3 from "crypto";
16086
- import fs17 from "fs";
16149
+ import fs16 from "fs";
16087
16150
  import readline2 from "readline";
16088
- import path11 from "path";
16151
+ import path10 from "path";
16089
16152
  var pendingServeHandoff = false;
16090
16153
  function consumePendingServeHandoff() {
16091
16154
  const pending = pendingServeHandoff;
@@ -16120,8 +16183,8 @@ var DEFAULT_QUOTA = {
16120
16183
  var PROJECT_MARKERS = [".git", "canonry.yaml", "canonry.yml", "package.json"];
16121
16184
  function cwdLooksLikeProject(dir) {
16122
16185
  const home = process.env.HOME ?? "";
16123
- if (home && path11.resolve(dir) === path11.resolve(home)) return false;
16124
- return PROJECT_MARKERS.some((marker) => fs17.existsSync(path11.join(dir, marker)));
16186
+ if (home && path10.resolve(dir) === path10.resolve(home)) return false;
16187
+ return PROJECT_MARKERS.some((marker) => fs16.existsSync(path10.join(dir, marker)));
16125
16188
  }
16126
16189
  var DEFAULT_AGENT_MODELS = {
16127
16190
  anthropic: "anthropic/claude-sonnet-4-6",
@@ -16152,8 +16215,8 @@ async function initCommand(opts) {
16152
16215
  return void 0;
16153
16216
  }
16154
16217
  const configDir = getConfigDir();
16155
- if (!fs17.existsSync(configDir)) {
16156
- fs17.mkdirSync(configDir, { recursive: true });
16218
+ if (!fs16.existsSync(configDir)) {
16219
+ fs16.mkdirSync(configDir, { recursive: true });
16157
16220
  }
16158
16221
  const bootstrapEnv = getBootstrapEnv(process.env, {
16159
16222
  GEMINI_API_KEY: opts?.geminiKey,
@@ -16275,7 +16338,7 @@ async function initCommand(opts) {
16275
16338
  const rawApiKey = `cnry_${crypto3.randomBytes(16).toString("hex")}`;
16276
16339
  const keyHash = crypto3.createHash("sha256").update(rawApiKey).digest("hex");
16277
16340
  const keyPrefix = rawApiKey.slice(0, 9);
16278
- const databasePath = path11.join(configDir, "data.db");
16341
+ const databasePath = path10.join(configDir, "data.db");
16279
16342
  const db = createClient(databasePath);
16280
16343
  migrate(db);
16281
16344
  db.insert(apiKeys).values({
@@ -16503,8 +16566,8 @@ async function repairPathsOnce(db, name, repair) {
16503
16566
  }
16504
16567
 
16505
16568
  // src/agent-plugin.ts
16506
- import fs18 from "fs";
16507
- import path12 from "path";
16569
+ import fs17 from "fs";
16570
+ import path11 from "path";
16508
16571
  var CANONRY_PLUGIN_ID = "canonry@canonry";
16509
16572
  var REQUIRED_SKILLS = ["canonry", "aero"];
16510
16573
  var AGENT_PLUGINS_SCHEMA = "https://agent-plugins.org/schemas/1.0.0/plugin.schema.json";
@@ -16548,7 +16611,7 @@ function isCanonryPluginId(value) {
16548
16611
  }
16549
16612
  function readJson(filePath) {
16550
16613
  try {
16551
- return JSON.parse(fs18.readFileSync(filePath, "utf8"));
16614
+ return JSON.parse(fs17.readFileSync(filePath, "utf8"));
16552
16615
  } catch {
16553
16616
  return null;
16554
16617
  }
@@ -16567,7 +16630,7 @@ function readCodexPluginConfigured(filePath) {
16567
16630
  try {
16568
16631
  let currentPlugin = null;
16569
16632
  let inPluginsTable = false;
16570
- for (const line of fs18.readFileSync(filePath, "utf8").split(/\r?\n/)) {
16633
+ for (const line of fs17.readFileSync(filePath, "utf8").split(/\r?\n/)) {
16571
16634
  const section = /^\s*\[plugins\.(?:"([^"]+)"|'([^']+)'|(\S+))\]\s*(?:#.*)?$/.exec(line);
16572
16635
  if (section) {
16573
16636
  const captures = section.slice(1, 4);
@@ -16600,21 +16663,21 @@ function readCodexPluginConfigured(filePath) {
16600
16663
  }
16601
16664
  }
16602
16665
  function verifiedPluginVersion(root, client) {
16603
- if (client === "codex" && fs18.existsSync(path12.join(root, "plugin.json"))) {
16604
- const manifest2 = readJson(path12.join(root, "plugin.json"));
16666
+ if (client === "codex" && fs17.existsSync(path11.join(root, "plugin.json"))) {
16667
+ const manifest2 = readJson(path11.join(root, "plugin.json"));
16605
16668
  if (manifest2 && typeof manifest2 === "object") {
16606
16669
  const plugin2 = manifest2;
16607
16670
  if (plugin2.$schema === AGENT_PLUGINS_SCHEMA) {
16608
16671
  if (plugin2.name !== "canonry" || typeof plugin2.version !== "string" || !parseSemver(plugin2.version)) {
16609
16672
  return null;
16610
16673
  }
16611
- const mcp2 = readJson(path12.join(root, "mcp.json"));
16674
+ const mcp2 = readJson(path11.join(root, "mcp.json"));
16612
16675
  if (!mcp2 || typeof mcp2 !== "object") return null;
16613
16676
  const portableMcp = mcp2;
16614
16677
  if (portableMcp.$schema !== AGENT_PLUGINS_MCP_SCHEMA || portableMcp.mcpServers?.canonry?.type !== "stdio" || portableMcp.mcpServers.canonry.command !== "canonry-mcp") {
16615
16678
  return null;
16616
16679
  }
16617
- return REQUIRED_SKILLS.every((name) => fs18.existsSync(path12.join(root, "skills", name, "SKILL.md"))) ? plugin2.version : null;
16680
+ return REQUIRED_SKILLS.every((name) => fs17.existsSync(path11.join(root, "skills", name, "SKILL.md"))) ? plugin2.version : null;
16618
16681
  }
16619
16682
  if (typeof plugin2.$schema === "string" && plugin2.$schema.startsWith("https://agent-plugins.org/schemas/")) {
16620
16683
  return null;
@@ -16622,20 +16685,20 @@ function verifiedPluginVersion(root, client) {
16622
16685
  }
16623
16686
  }
16624
16687
  const manifestDir = client === "claude-code" ? ".claude-plugin" : ".codex-plugin";
16625
- const manifest = readJson(path12.join(root, manifestDir, "plugin.json"));
16688
+ const manifest = readJson(path11.join(root, manifestDir, "plugin.json"));
16626
16689
  if (!manifest || typeof manifest !== "object") return null;
16627
16690
  const plugin = manifest;
16628
16691
  if (plugin.name !== "canonry" || typeof plugin.version !== "string" || !parseSemver(plugin.version) || plugin.skills !== "./skills/" || plugin.mcpServers !== "./.mcp.json") {
16629
16692
  return null;
16630
16693
  }
16631
- const mcp = readJson(path12.join(root, ".mcp.json"));
16694
+ const mcp = readJson(path11.join(root, ".mcp.json"));
16632
16695
  if (!mcp || typeof mcp !== "object") return null;
16633
16696
  const canonryServer = mcp.mcpServers?.canonry;
16634
16697
  if (canonryServer?.command !== "canonry-mcp") return null;
16635
- return REQUIRED_SKILLS.every((name) => fs18.existsSync(path12.join(root, "skills", name, "SKILL.md"))) ? plugin.version : null;
16698
+ return REQUIRED_SKILLS.every((name) => fs17.existsSync(path11.join(root, "skills", name, "SKILL.md"))) ? plugin.version : null;
16636
16699
  }
16637
16700
  function readClaudeUserInstallPaths(claudeConfigDir) {
16638
- const parsed = readJson(path12.join(claudeConfigDir, "plugins", "installed_plugins.json"));
16701
+ const parsed = readJson(path11.join(claudeConfigDir, "plugins", "installed_plugins.json"));
16639
16702
  if (!parsed || typeof parsed !== "object") return [];
16640
16703
  const plugins = parsed.plugins;
16641
16704
  if (!plugins || typeof plugins !== "object") return [];
@@ -16649,7 +16712,7 @@ function readClaudeUserInstallPaths(claudeConfigDir) {
16649
16712
  }
16650
16713
  function listDirectories(dir) {
16651
16714
  try {
16652
- return fs18.readdirSync(dir, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => path12.join(dir, entry.name));
16715
+ return fs17.readdirSync(dir, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => path11.join(dir, entry.name));
16653
16716
  } catch {
16654
16717
  return [];
16655
16718
  }
@@ -16661,8 +16724,8 @@ function verifiedClaudeVersion(claudeConfigDir) {
16661
16724
  return newestVersion(readClaudeUserInstallPaths(claudeConfigDir).map((installPath) => verifiedPluginVersion(installPath, "claude-code")).filter((version) => version !== null));
16662
16725
  }
16663
16726
  function verifiedCodexVersion(codexHome) {
16664
- const pluginCache = path12.join(codexHome, "plugins", "cache", "canonry", "canonry");
16665
- const versionedRoots = listDirectories(pluginCache).map((installPath) => ({ installPath, version: path12.basename(installPath) })).filter((candidate) => parseSemver(candidate.version) !== null).sort((left, right) => compareSemver(left.version, right.version));
16727
+ const pluginCache = path11.join(codexHome, "plugins", "cache", "canonry", "canonry");
16728
+ const versionedRoots = listDirectories(pluginCache).map((installPath) => ({ installPath, version: path11.basename(installPath) })).filter((candidate) => parseSemver(candidate.version) !== null).sort((left, right) => compareSemver(left.version, right.version));
16666
16729
  const active = versionedRoots.at(-1);
16667
16730
  if (!active) return verifiedPluginVersion(pluginCache, "codex");
16668
16731
  const manifestVersion = verifiedPluginVersion(active.installPath, "codex");
@@ -16670,12 +16733,12 @@ function verifiedCodexVersion(codexHome) {
16670
16733
  }
16671
16734
  function detectCanonryAgentPlugin(opts = {}) {
16672
16735
  const home = opts.home?.trim() || null;
16673
- const claudeConfigDir = opts.claudeConfigDir?.trim() || (home ? path12.join(home, ".claude") : null);
16674
- const codexHome = opts.codexHome?.trim() || (home ? path12.join(home, ".codex") : null);
16736
+ const claudeConfigDir = opts.claudeConfigDir?.trim() || (home ? path11.join(home, ".claude") : null);
16737
+ const codexHome = opts.codexHome?.trim() || (home ? path11.join(home, ".codex") : null);
16675
16738
  const configuredClients = [];
16676
16739
  const verifiedClients = [];
16677
16740
  const verifiedClientVersions = {};
16678
- const claudeConfigured = claudeConfigDir ? readClaudePluginConfigured(path12.join(claudeConfigDir, "settings.json")) : false;
16741
+ const claudeConfigured = claudeConfigDir ? readClaudePluginConfigured(path11.join(claudeConfigDir, "settings.json")) : false;
16679
16742
  if (claudeConfigured) {
16680
16743
  configuredClients.push("claude-code");
16681
16744
  const version = claudeConfigDir ? verifiedClaudeVersion(claudeConfigDir) : null;
@@ -16684,7 +16747,7 @@ function detectCanonryAgentPlugin(opts = {}) {
16684
16747
  verifiedClientVersions["claude-code"] = version;
16685
16748
  }
16686
16749
  }
16687
- const codexConfigured = codexHome ? readCodexPluginConfigured(path12.join(codexHome, "config.toml")) : false;
16750
+ const codexConfigured = codexHome ? readCodexPluginConfigured(path11.join(codexHome, "config.toml")) : false;
16688
16751
  if (codexConfigured) {
16689
16752
  configuredClients.push("codex");
16690
16753
  const version = codexHome ? verifiedCodexVersion(codexHome) : null;
@@ -18122,14 +18185,14 @@ Usage: ${usage}`, {
18122
18185
  }
18123
18186
  }
18124
18187
  ];
18125
- function siteHealthAlias(sourcePath, path13, usage) {
18188
+ function siteHealthAlias(sourcePath, path12, usage) {
18126
18189
  const source = TECHNICAL_AEO_CLI_COMMANDS_BASE.find(
18127
18190
  (candidate) => candidate.path.join(" ") === sourcePath.join(" ")
18128
18191
  );
18129
18192
  if (!source) throw new Error(`Missing Site Health compatibility source: ${sourcePath.join(" ")}`);
18130
18193
  return {
18131
18194
  ...source,
18132
- path: path13,
18195
+ path: path12,
18133
18196
  usage,
18134
18197
  run: async (input) => {
18135
18198
  try {
@@ -18140,7 +18203,7 @@ function siteHealthAlias(sourcePath, path13, usage) {
18140
18203
  throw usageError(`${firstLine}
18141
18204
  Usage: ${usage}`, {
18142
18205
  message: error.message,
18143
- details: { ...error.details, command: path13.join("."), usage }
18206
+ details: { ...error.details, command: path12.join("."), usage }
18144
18207
  });
18145
18208
  }
18146
18209
  }
@@ -18423,7 +18486,7 @@ function printVisibilityStats(data) {
18423
18486
  }
18424
18487
 
18425
18488
  // src/cli-commands/visibility-stats.ts
18426
- var USAGE5 = "canonry visibility-stats <project> [--since <iso>] [--until <iso>] [--month <YYYY-MM>] [--last-runs <n>] [--by-provider] [--share-of-voice] [--query-class branded|non-brand] [--format json|jsonl]";
18489
+ var USAGE4 = "canonry visibility-stats <project> [--since <iso>] [--until <iso>] [--month <YYYY-MM>] [--last-runs <n>] [--by-provider] [--share-of-voice] [--query-class branded|non-brand] [--format json|jsonl]";
18427
18490
  function parseQueryClass(value) {
18428
18491
  if (value === void 0 || value === "") return void 0;
18429
18492
  if (value !== "branded" && value !== "non-brand") {
@@ -18460,7 +18523,7 @@ Usage: ${COMPARE_USAGE}`, {
18460
18523
  var VISIBILITY_STATS_CLI_COMMANDS = [
18461
18524
  {
18462
18525
  path: ["visibility-stats"],
18463
- usage: USAGE5,
18526
+ usage: USAGE4,
18464
18527
  options: {
18465
18528
  since: stringOption(),
18466
18529
  until: stringOption(),
@@ -18471,14 +18534,14 @@ var VISIBILITY_STATS_CLI_COMMANDS = [
18471
18534
  "query-class": stringOption()
18472
18535
  },
18473
18536
  run: async (input) => {
18474
- const project2 = requireProject(input, "visibility-stats", USAGE5);
18537
+ const project2 = requireProject(input, "visibility-stats", USAGE4);
18475
18538
  await showVisibilityStats(project2, {
18476
18539
  since: getString(input.values, "since"),
18477
18540
  until: getString(input.values, "until"),
18478
18541
  month: getString(input.values, "month"),
18479
18542
  lastRuns: parseIntegerOption(input, "last-runs", {
18480
18543
  command: "visibility-stats",
18481
- usage: USAGE5,
18544
+ usage: USAGE4,
18482
18545
  message: "--last-runs must be an integer"
18483
18546
  }),
18484
18547
  byProvider: getBoolean(input.values, "by-provider"),
@@ -18513,7 +18576,7 @@ var VISIBILITY_STATS_CLI_COMMANDS = [
18513
18576
  ];
18514
18577
 
18515
18578
  // src/cli-commands/wordpress.ts
18516
- import fs19 from "fs";
18579
+ import fs18 from "fs";
18517
18580
 
18518
18581
  // src/commands/wordpress.ts
18519
18582
  function getClient28() {
@@ -18752,12 +18815,12 @@ async function wordpressSetMeta(project2, body) {
18752
18815
  printPageDetail(result);
18753
18816
  }
18754
18817
  async function wordpressBulkSetMeta(project2, opts) {
18755
- const fs20 = await import("fs/promises");
18756
- const path13 = await import("path");
18757
- const filePath = path13.resolve(opts.from);
18818
+ const fs19 = await import("fs/promises");
18819
+ const path12 = await import("path");
18820
+ const filePath = path12.resolve(opts.from);
18758
18821
  let raw;
18759
18822
  try {
18760
- raw = await fs20.readFile(filePath, "utf8");
18823
+ raw = await fs19.readFile(filePath, "utf8");
18761
18824
  } catch {
18762
18825
  throw new CliError({
18763
18826
  code: "FILE_READ_ERROR",
@@ -18854,13 +18917,13 @@ async function wordpressSetSchema(project2, body) {
18854
18917
  printManualAssist(`Schema update for "${body.slug}"`, result);
18855
18918
  }
18856
18919
  async function wordpressSchemaDeploy(project2, opts) {
18857
- const fs20 = await import("fs/promises");
18858
- const path13 = await import("path");
18920
+ const fs19 = await import("fs/promises");
18921
+ const path12 = await import("path");
18859
18922
  const yaml = await loadYamlModule();
18860
- const filePath = path13.resolve(opts.profile);
18923
+ const filePath = path12.resolve(opts.profile);
18861
18924
  let raw;
18862
18925
  try {
18863
- raw = await fs20.readFile(filePath, "utf8");
18926
+ raw = await fs19.readFile(filePath, "utf8");
18864
18927
  } catch {
18865
18928
  throw new CliError({
18866
18929
  code: "FILE_READ_ERROR",
@@ -18965,13 +19028,13 @@ async function wordpressOnboard(project2, opts) {
18965
19028
  }
18966
19029
  let profileData;
18967
19030
  if (opts.profile) {
18968
- const fs20 = await import("fs/promises");
18969
- const path13 = await import("path");
19031
+ const fs19 = await import("fs/promises");
19032
+ const path12 = await import("path");
18970
19033
  const yaml = await loadYamlModule();
18971
- const filePath = path13.resolve(opts.profile);
19034
+ const filePath = path12.resolve(opts.profile);
18972
19035
  let raw;
18973
19036
  try {
18974
- raw = await fs20.readFile(filePath, "utf8");
19037
+ raw = await fs19.readFile(filePath, "utf8");
18975
19038
  } catch {
18976
19039
  throw new CliError({
18977
19040
  code: "FILE_READ_ERROR",
@@ -19120,7 +19183,7 @@ function resolveContent(input, command, usage, options) {
19120
19183
  }
19121
19184
  if (contentFile) {
19122
19185
  try {
19123
- return fs19.readFileSync(contentFile, "utf-8");
19186
+ return fs18.readFileSync(contentFile, "utf-8");
19124
19187
  } catch (error) {
19125
19188
  const message = describeError(error);
19126
19189
  throw usageError(`Error: could not read --content-file "${contentFile}": ${message}`, {
@@ -20429,7 +20492,6 @@ var REGISTERED_CLI_COMMANDS = [
20429
20492
  ...BACKLINKS_CLI_COMMANDS,
20430
20493
  ...SYSTEM_CLI_COMMANDS,
20431
20494
  ...PROJECT_CLI_COMMANDS,
20432
- ...REPORT_CLI_COMMANDS,
20433
20495
  ...ORGANIC_EVIDENCE_CLI_COMMANDS,
20434
20496
  ...QUERY_CLI_COMMANDS,
20435
20497
  ...KEYWORD_CLI_COMMANDS,
@@ -20494,7 +20556,7 @@ function buildSetupNudgeLine(input) {
20494
20556
 
20495
20557
  // src/cli.ts
20496
20558
  import { createRequire as createRequire2 } from "module";
20497
- var USAGE6 = `
20559
+ var USAGE5 = `
20498
20560
  cnry \u2014 Page Health and AI visibility CLI ('canonry' also works)
20499
20561
 
20500
20562
  Usage: cnry <command> [options]
@@ -20608,7 +20670,7 @@ function telemetryErrorCode(err) {
20608
20670
  }
20609
20671
  async function runCli(args = process.argv.slice(2)) {
20610
20672
  if (args.length === 0 || args[0] === "--help" || args[0] === "-h") {
20611
- console.log(USAGE6);
20673
+ console.log(USAGE5);
20612
20674
  return 0;
20613
20675
  }
20614
20676
  if (args.includes("--version") || args.includes("-v")) {