@canonry/canonry 7.97.0 → 7.97.2

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 (25) hide show
  1. package/assets/agent-workspace/skills/canonry/references/canonry-cli.md +1 -1
  2. package/assets/agent-workspace/skills/canonry/references/google-business-profile.md +9 -1
  3. package/assets/agent-workspace/skills/canonry/references/server-side-traffic.md +28 -23
  4. package/dist/{backfill-ZSLOPGNJ.js → backfill-6UMNMA5D.js} +3 -3
  5. package/dist/{chunk-HL64C53O.js → chunk-BYPNVDJE.js} +1 -1
  6. package/dist/{chunk-NKJLQ6ED.js → chunk-CD7WROGG.js} +1 -1
  7. package/dist/{chunk-VRDN5TH7.js → chunk-FVA3QBUJ.js} +1 -1
  8. package/dist/{chunk-JJH55CAR.js → chunk-I37MDUG5.js} +3 -3
  9. package/dist/{chunk-FFPD6DWR.js → chunk-KIUXAGME.js} +1 -1
  10. package/dist/{chunk-VNQHCJXG.js → chunk-NBZ7GLTP.js} +1 -1
  11. package/dist/{chunk-7VPF373L.js → chunk-RQMGGRIO.js} +38 -2
  12. package/dist/{chunk-WQJCGMHW.js → chunk-WOHQNWVO.js} +14 -14
  13. package/dist/{chunk-PL5T2LOA.js → chunk-XJQNALKR.js} +6 -6
  14. package/dist/{cli-commands-WPTOQUHN.js → cli-commands-WCKKUVFG.js} +1 -1
  15. package/dist/cli.js +2 -2
  16. package/dist/{dashboard-BC4XZVJW.js → dashboard-A2GTXYCN.js} +1 -1
  17. package/dist/{demo-JMOSQAAH.js → demo-PQUQM6D6.js} +1 -1
  18. package/dist/{demo-server-YPDXH7HV.js → demo-server-2EIJCN6D.js} +2 -2
  19. package/dist/index.js +6 -6
  20. package/dist/{init-OCKHQ7IL.js → init-T7KF667H.js} +1 -1
  21. package/dist/{intelligence-service-T5DWIMJS.js → intelligence-service-GW55NFVE.js} +2 -2
  22. package/dist/{serve-MH7ZC44A.js → serve-NHQ4J6IG.js} +7 -7
  23. package/dist/{session-P6STOUZI.js → session-L4CT3XZQ.js} +3 -3
  24. package/dist/{tools-AJWV72XT.js → tools-OIVQXP5C.js} +2 -2
  25. package/package.json +1 -1
@@ -1153,7 +1153,7 @@ upgrade reads high on that side.
1153
1153
 
1154
1154
  ## Google Analytics 4
1155
1155
 
1156
- GA4 integration supports service-account auth and OAuth (`canonry google connect <project> --type ga4`). With OAuth, `ga properties` lists the readable properties so the numeric id `ga connect --property-id` needs can be discovered without leaving canonry. The service account must have Viewer access on the GA4 property. `ga sync` writes the traffic tables (`gaTrafficSnapshots`, `gaAiReferrals`, `gaSocialReferrals`, `gaTrafficSummaries`) plus the GA4 Search Console landing-page snapshot (`gaSearchLandingWindows`, `gaSearchLandingPages`); every subsequent read command queries the local store rather than re-fetching from GA4, so reads are fast and quotaless. AI-referral rows are sessions GA4 puts in its `AI Assistant` channel (medium `ai-assistant`, since 2026-05-13, not retroactive) plus sessions whose source is an AI engine's host or a subdomain of it (`chatgpt.com`, `www.perplexity.ai`, `gemini.google.com`, `claude.ai`, `copilot.microsoft.com`, `grok.com`, `meta.ai`, `you.com`, …), its bare name (`chatgpt`, `gemini`, `grok`), its official Android app id, bare or as `android-app://` (`com.openai.chatgpt`, `com.microsoft.copilot`), or, for ChatGPT, Perplexity, Claude, DeepSeek and Phind, a tag that starts with the name or host (`perplexity_ai`, `chatgpt.com_ads`). These cover older history and AI visits GA4 files elsewhere. An engine name inside another source is never matched, so ngrok tunnels, `philanthropic.org` and the Gemini exchange stay out. A channel row whose source names no engine is kept under its own source and counted in every AI total; visits that send no referrer still land in Direct. Rows are tracked across three GA4 attribution dimensions (`session` / `first_user` / `manual_utm`; the manual UTM lens matches sources only, since GA4 has no channel for it) and joined to landing pages. Social referrals are split Organic vs Paid via GA4's `sessionDefaultChannelGroup`. Synced rows carry no GA4 property, so anything that changes the property a project resolves to (`ga connect` to another property, `ga disconnect`, or `google disconnect --type ga4` with no service account behind it) deletes the project's GA rows; the next `ga sync` refills them from the new property. All commands support `--format json`.
1156
+ GA4 integration supports service-account auth and OAuth (`canonry google connect <project> --type ga4`). With OAuth, `ga properties` lists the readable properties so the numeric id `ga connect --property-id` needs can be discovered without leaving canonry. The service account must have Viewer access on the GA4 property. `ga sync` writes the traffic tables (`gaTrafficSnapshots`, `gaAiReferrals`, `gaSocialReferrals`, `gaTrafficSummaries`) plus the GA4 Search Console landing-page snapshot (`gaSearchLandingWindows`, `gaSearchLandingPages`); every subsequent read command queries the local store rather than re-fetching from GA4, so reads are fast and quotaless. AI-referral rows are sessions GA4 puts in its `AI Assistant` channel (medium `ai-assistant`, since 2026-05-13, not retroactive) plus sessions whose source is an AI engine's host or a subdomain of it (`chatgpt.com`, `www.perplexity.ai`, `gemini.google.com`, `claude.ai`, `copilot.microsoft.com`, `grok.com`, `meta.ai`, `you.com`, …), its bare name (`chatgpt`, `gemini`, `grok`), its official Android app id, bare or as `android-app://` (`com.openai.chatgpt`, `com.microsoft.copilot`), or, for ChatGPT, Perplexity, Claude, DeepSeek and Phind, a tag that starts with the name or host (`perplexity_ai`, `chatgpt.com_ads`). These cover older history and AI visits GA4 files elsewhere. An engine name inside another source is never matched, so unrelated tunnel hosts, `philanthropic.org` and the Gemini exchange stay out. A channel row whose source names no engine is kept under its own source and counted in every AI total; visits that send no referrer still land in Direct. Rows are tracked across three GA4 attribution dimensions (`session` / `first_user` / `manual_utm`; the manual UTM lens matches sources only, since GA4 has no channel for it) and joined to landing pages. Social referrals are split Organic vs Paid via GA4's `sessionDefaultChannelGroup`. Synced rows carry no GA4 property, so anything that changes the property a project resolves to (`ga connect` to another property, `ga disconnect`, or `google disconnect --type ga4` with no service account behind it) deletes the project's GA rows; the next `ga sync` refills them from the new property. All commands support `--format json`.
1157
1157
 
1158
1158
  ```bash
1159
1159
  cnry ga connect <project> --property-id <id> --key-file ./sa-key.json
@@ -106,7 +106,15 @@ Rules that hold for both sources:
106
106
 
107
107
  Subscribe: `cnry notify add <project> --webhook <url> --events review.negative,review.rating-dropped`. Discord and Slack webhook URLs get a formatted message; any other URL gets the signed JSON payload. The doctor check warns only when a project subscribes to review events and some location has no review source at all; missing v4 access alone reports as skipped, since it is the normal state.
108
108
 
109
- **Account-credential gotcha:** API calls use your **Application Default Credentials** (`gcloud auth application-default login` → `print-access-token`), while `gcloud services enable` uses the separate **gcloud CLI account** (`gcloud config get-value account`). These can be different identities. Verify the token's real account with `curl "https://www.googleapis.com/oauth2/v1/tokeninfo?access_token=$TOKEN"` before concluding anything about access — a "wrong account" symptom is often just the two credential stores disagreeing.
109
+ **Account-credential gotcha:** Application Default Credentials (ADC) and the
110
+ gcloud CLI have separate authentication configurations. An API diagnostic
111
+ using ADC can therefore run as a different identity from `gcloud services
112
+ enable`, which uses the CLI account shown by `gcloud config get-value account`.
113
+ Confirm which credential source the diagnostic uses and which account was
114
+ authorized for it before concluding that API access is missing. If the local
115
+ ADC identity is wrong, have the operator authorize the intended account with
116
+ `gcloud auth application-default login`; changing the CLI's active account
117
+ does not change ADC. See [Google's ADC configuration and search order](https://cloud.google.com/docs/authentication/application-default-credentials).
110
118
 
111
119
  ### Create OAuth client credentials
112
120
 
@@ -482,39 +482,44 @@ same-origin assets, or the account is on Workers Paid.
482
482
 
483
483
  ### Excluding static assets from the route
484
484
 
485
- A route with NO script disables Workers on that path, and Cloudflare applies
486
- the most specific match. This removes the bundle without losing any crawler
487
- evidence, because crawlers request pages, not JS chunks.
485
+ A route with no Worker assigned bypasses Workers on that path. Cloudflare's
486
+ most-specific-match rule lets an asset route override the broader Canonry
487
+ route. This reduces invocations while retaining page traffic; requests to the
488
+ excluded asset paths are intentionally absent from Canonry's evidence.
488
489
 
489
- ```bash
490
- # assets -> no worker. Omitting "script" is what disables it.
491
- curl -s -X POST -H "Authorization: Bearer $CF_TOKEN" -H "Content-Type: application/json" \
492
- --data '{"pattern":"<host>/_nuxt/*"}' \
493
- "https://api.cloudflare.com/client/v4/zones/$ZONE/workers/routes"
490
+ Use the zone's route management or the [Workers Routes API](https://developers.cloudflare.com/api/resources/workers/subresources/routes/methods/create/)
491
+ to create the exclusion. For a Nuxt site, the route creation payload is:
492
+
493
+ ```json
494
+ {"pattern":"<host>/_nuxt/*"}
494
495
  ```
495
496
 
496
- Prefixes by framework: `/_nuxt/*` Nuxt, `/_next/*` Next.js, plus `/assets/*`,
497
- `/static/*`, `/build/*`.
497
+ Replace `<host>` with the canonical hostname and omit `script` so no Worker is
498
+ assigned. Verify the saved route has the intended pattern and no Worker. Keep
499
+ the broader `<host>/*` route assigned to the Canonry Worker. Other asset
500
+ prefixes include `/_next/*` for Next.js, `/assets/*`, `/static/*`, and `/build/*`.
501
+ See [Cloudflare's route matching rules](https://developers.cloudflare.com/workers/configuration/routing/routes/#matching-behavior).
498
502
 
499
503
  **The Worker's own "Domains and Routes" tab cannot do this.** That screen only
500
504
  attaches routes TO that Worker, so adding the asset path there routes assets
501
- INTO the Worker and doubles the load. Asset exclusion is zone-level: the zone's
502
- Workers Routes page, or the API above.
505
+ INTO the Worker. Asset exclusion must leave the Worker unassigned, using zone
506
+ route management or the API above.
503
507
 
504
- ### Fail open defaults to OFF
508
+ ### Verify the route's fail mode
505
509
 
506
- `request_limit_fail_open` is per route and defaults to `false`. Left off, a
507
- Worker error or an exhausted request allowance returns 5xx for every request on
508
- that route, which on a catch-all is the whole site. Setting it is not optional
509
- and it is not the default, so verify rather than assume:
510
+ For a Worker used only to collect traffic, configure the route to **fail open**.
511
+ Cloudflare then bypasses the Worker if the Free account exhausts its daily
512
+ request allowance; fail closed returns a Cloudflare `1027` error page. This
513
+ keeps the origin available while traffic collection is interrupted. A Worker
514
+ that also enforces security needs its own fail-mode decision.
510
515
 
511
- ```bash
512
- curl -s -H "Authorization: Bearer $CF_TOKEN" \
513
- "https://api.cloudflare.com/client/v4/zones/$ZONE/workers/routes" \
514
- | jq '.result[] | {pattern, script, request_limit_fail_open}'
515
- ```
516
+ In the Cloudflare dashboard, inspect the corresponding route and set its fail
517
+ mode to open, then reopen it to confirm the saved setting. The API's
518
+ `request_limit_fail_open` field represents this route setting; verify it is
519
+ `true` when inspecting route state. Do not infer the setting from a successful
520
+ deployment. See [Cloudflare's daily request limits and route fail modes](https://developers.cloudflare.com/workers/platform/limits/#daily-requests).
516
521
 
517
- Both route operations need `Zone | Workers Routes | Edit` on the token.
522
+ API route changes require `Zone | Workers Routes | Edit` permission.
518
523
 
519
524
  ```bash
520
525
  npm install -g wrangler@latest
@@ -10,8 +10,8 @@ import {
10
10
  backfillSnapshotAttributionCommand,
11
11
  backfillTrafficClassificationCommand,
12
12
  replayQueryAuditLog
13
- } from "./chunk-JJH55CAR.js";
14
- import "./chunk-FFPD6DWR.js";
13
+ } from "./chunk-I37MDUG5.js";
14
+ import "./chunk-KIUXAGME.js";
15
15
  import "./chunk-PNVI2UYZ.js";
16
16
  import "./chunk-HGMYEDAQ.js";
17
17
  import "./chunk-QP6RYMZR.js";
@@ -19,7 +19,7 @@ import "./chunk-RIQXJDGZ.js";
19
19
  import {
20
20
  backfillProjectAnswerMentions,
21
21
  backfillProjectAnswerMentionsInChunks
22
- } from "./chunk-7VPF373L.js";
22
+ } from "./chunk-RQMGGRIO.js";
23
23
  import "./chunk-6TIJFZX5.js";
24
24
  import "./chunk-D4ABSOQG.js";
25
25
  import "./chunk-VDWTOMU4.js";
@@ -5,7 +5,7 @@ import {
5
5
  isStoredPageReadTool,
6
6
  isStoredReadTool,
7
7
  truncateToolResult
8
- } from "./chunk-NKJLQ6ED.js";
8
+ } from "./chunk-CD7WROGG.js";
9
9
  import {
10
10
  CANONRY_MCP_TOOLKITS,
11
11
  resolveAeroSkillDir
@@ -10,7 +10,7 @@ import {
10
10
  } from "./chunk-HGMYEDAQ.js";
11
11
  import {
12
12
  buildOpenApiDocument
13
- } from "./chunk-7VPF373L.js";
13
+ } from "./chunk-RQMGGRIO.js";
14
14
  import {
15
15
  DEFAULT_COMPETITOR_AUTO_ALIAS_MODE,
16
16
  MeasurementPortfolioLists,
@@ -17,7 +17,7 @@ import {
17
17
  mergeGscQueryTotalsWithFallback,
18
18
  readGscQueryDailyRows,
19
19
  readLatestGscDataDate
20
- } from "./chunk-7VPF373L.js";
20
+ } from "./chunk-RQMGGRIO.js";
21
21
  import {
22
22
  competitors,
23
23
  gbpDailyMetrics,
@@ -8,7 +8,7 @@ import {
8
8
  reparseStoredResult4,
9
9
  reparseStoredResult5,
10
10
  resolveStoredApiResponse
11
- } from "./chunk-FFPD6DWR.js";
11
+ } from "./chunk-KIUXAGME.js";
12
12
  import {
13
13
  loadConfig
14
14
  } from "./chunk-PNVI2UYZ.js";
@@ -24,7 +24,7 @@ import {
24
24
  createRunCompetitorResolver,
25
25
  readMarketCompetitorNames,
26
26
  refreshSnapshotMentionIdentity
27
- } from "./chunk-7VPF373L.js";
27
+ } from "./chunk-RQMGGRIO.js";
28
28
  import {
29
29
  RawEventSampleEventTypes,
30
30
  auditLog,
@@ -429,7 +429,7 @@ No DB writes performed. Re-run without --dry-run to apply.`);
429
429
  }
430
430
  }
431
431
  async function backfillInsightsCommand(project, opts) {
432
- const { IntelligenceService } = await import("./intelligence-service-T5DWIMJS.js");
432
+ const { IntelligenceService } = await import("./intelligence-service-GW55NFVE.js");
433
433
  const config = loadConfig();
434
434
  const db = createClient(config.database);
435
435
  migrate(db);
@@ -7,7 +7,7 @@ import {
7
7
  mergeSplitJourneyVisitors,
8
8
  repairAiReferralArrivalsOnStartup,
9
9
  writeUnrecognizedAgentBuckets
10
- } from "./chunk-7VPF373L.js";
10
+ } from "./chunk-RQMGGRIO.js";
11
11
  import {
12
12
  AGENT_TRUST_RULES_VERSION,
13
13
  BROWSER_SHAPED_AGENT_MARKERS,
@@ -47,7 +47,7 @@ function queueServeHandoff() {
47
47
  async function runPendingServeHandoff(format) {
48
48
  if (!pendingServeHandoff) return;
49
49
  pendingServeHandoff = false;
50
- const { serveCommand } = await import("./serve-MH7ZC44A.js");
50
+ const { serveCommand } = await import("./serve-NHQ4J6IG.js");
51
51
  await serveCommand(format);
52
52
  }
53
53
 
@@ -47162,10 +47162,45 @@ function pinnedAgent(addresses) {
47162
47162
  }
47163
47163
 
47164
47164
  // ../api-routes/src/gbp-hotel-policy.ts
47165
+ var WORD = String.raw`[\p{L}\p{N}&.'’-]+`;
47166
+ var VERB_USES = [
47167
+ /\bdeals?\s+with\b/gu,
47168
+ new RegExp(
47169
+ String.raw`\b(?:does|do|did|will|would|can|could|may|might|should|must|to)\s+(?:not\s+)?(?:${WORD}\s+){0,4}?offer\b`,
47170
+ "gu"
47171
+ ),
47172
+ new RegExp(String.raw`\bwhat\s+(?:${WORD}\s+){0,3}?offers?\b`, "gu"),
47173
+ /\boffers?(?=\s+(?:a|an|the|free|both|several|written|financing|warrant(?:y|ies)|inspections?|services?|repairs?|coverage|options?|support)\b)/gu
47174
+ ];
47175
+ function withoutVerbUses(text) {
47176
+ return VERB_USES.reduce((value, verb) => value.replace(verb, " "), text);
47177
+ }
47165
47178
  function hotelEditorialText(value) {
47166
47179
  const text = decodeHTML(value).normalize("NFKC").toLowerCase();
47167
47180
  return text.trim().length > 0 && !/\b(?:offers?|deals?|promotions?|discounts?|coupons?|promo\s*codes?|special\s+rates?|book\s+now|save\s+\d+)\b|\d+\s*%\s*off/iu.test(
47168
- text
47181
+ withoutVerbUses(text)
47182
+ );
47183
+ }
47184
+ var PROMOTION = new RegExp(
47185
+ [
47186
+ String.raw`\b(?:promotions?|discounts?|coupons?|promo\s*codes?|special\s+rates?|book\s+now|save\s+\d+)\b`,
47187
+ String.raw`\d+\s*%\s*off`,
47188
+ String.raw`\b(?:special|exclusive|limited[-\s]+time|seasonal|holiday|weekend|package|hot|last[-\s]+minute|early[-\s]+bird|flash|daily|weekly|monthly|travel|room|hotel|stay|spa|dining|best|great|top|our|these|latest|current|view|see|explore|browse|all)\s+(?:offers?|deals?)\b`,
47189
+ String.raw`\b(?:offers?|deals?)\s+(?:end(?:s|ing)?|expire[sd]?|expiring|code)\b`,
47190
+ String.raw`\b(?:deal|offer)\s+of\s+the\s+(?:day|week|month)\b`
47191
+ ].join("|"),
47192
+ "u"
47193
+ );
47194
+ function promotionFree(value) {
47195
+ return !PROMOTION.test(decodeHTML(value).normalize("NFKC").toLowerCase());
47196
+ }
47197
+ var TAG = String.raw`<(?:[^"'<>]|"[^"]*"|'[^']*')*>`;
47198
+ var SENTENCES = /(<(p|li)\b(?:[^"'<>]|"[^"]*"|'[^']*')*>)([\s\S]*?)(<\/\2\s*>)/giu;
47199
+ var SENTENCE_PARTS = new RegExp(String.raw`(<a\b(?:[^"'<>]|"[^"]*"|'[^']*')*>[\s\S]*?<\/a\s*>|${TAG})|[^<]+`, "giu");
47200
+ function withoutSentenceText(html) {
47201
+ return html.replace(
47202
+ SENTENCES,
47203
+ (_whole, open, _tag, inner, close) => open + inner.replace(SENTENCE_PARTS, (_part, markup) => markup ?? " ") + close
47169
47204
  );
47170
47205
  }
47171
47206
  var JSON_STRING = /"(?:\\.|[^"\\])*"/gu;
@@ -47264,7 +47299,8 @@ function editorialHtml(html) {
47264
47299
  return `<script${attributes}>${normalized}</script>`;
47265
47300
  }
47266
47301
  );
47267
- return valid && hotelEditorialText(text) && hotelEditorialText(decodePercentRuns(text));
47302
+ const markup = withoutSentenceText(text);
47303
+ return valid && hotelEditorialText(markup) && hotelEditorialText(decodePercentRuns(markup)) && promotionFree(text) && promotionFree(decodePercentRuns(text));
47268
47304
  }
47269
47305
  async function hotelEditorialDestination(domain, summary3, articleUrl, fetchImpl = createGuardedFetch()) {
47270
47306
  try {
@@ -728,7 +728,7 @@ var DEMO_CLI_COMMANDS = [{
728
728
  options: { host: stringOption(), port: stringOption(), "trust-proxy": multiStringOption() },
729
729
  allowPositionals: false,
730
730
  run: async (input) => {
731
- const { demoCommand } = await import("./demo-JMOSQAAH.js");
731
+ const { demoCommand } = await import("./demo-PQUQM6D6.js");
732
732
  await demoCommand({
733
733
  host: getString(input.values, "host"),
734
734
  port: getString(input.values, "port"),
@@ -749,7 +749,7 @@ var BACKFILL_CLI_COMMANDS = [
749
749
  allowPositionals: false,
750
750
  supportsDryRun: true,
751
751
  run: async (input) => {
752
- const { backfillAnswerVisibilityCommand } = await import("./backfill-ZSLOPGNJ.js");
752
+ const { backfillAnswerVisibilityCommand } = await import("./backfill-6UMNMA5D.js");
753
753
  await backfillAnswerVisibilityCommand({
754
754
  project: getString(input.values, "project"),
755
755
  dryRun: input.dryRun,
@@ -766,7 +766,7 @@ var BACKFILL_CLI_COMMANDS = [
766
766
  allowPositionals: false,
767
767
  supportsDryRun: true,
768
768
  run: async (input) => {
769
- const { backfillAnswerMentionsCommand } = await import("./backfill-ZSLOPGNJ.js");
769
+ const { backfillAnswerMentionsCommand } = await import("./backfill-6UMNMA5D.js");
770
770
  await backfillAnswerMentionsCommand({
771
771
  project: getString(input.values, "project"),
772
772
  dryRun: input.dryRun,
@@ -784,7 +784,7 @@ var BACKFILL_CLI_COMMANDS = [
784
784
  },
785
785
  supportsDryRun: true,
786
786
  run: async (input) => {
787
- const { backfillInsightsCommand } = await import("./backfill-ZSLOPGNJ.js");
787
+ const { backfillInsightsCommand } = await import("./backfill-6UMNMA5D.js");
788
788
  const usage = "canonry backfill insights <project> [--from-run <id>] [--to-run <id>] [--since <date>] [--dry-run] [--format json]";
789
789
  const project3 = requireProject(input, "backfill insights", usage);
790
790
  await backfillInsightsCommand(project3, {
@@ -804,7 +804,7 @@ var BACKFILL_CLI_COMMANDS = [
804
804
  },
805
805
  allowPositionals: false,
806
806
  run: async (input) => {
807
- const { backfillNormalizedPathsCommand } = await import("./backfill-ZSLOPGNJ.js");
807
+ const { backfillNormalizedPathsCommand } = await import("./backfill-6UMNMA5D.js");
808
808
  await backfillNormalizedPathsCommand({
809
809
  project: getString(input.values, "project"),
810
810
  format: input.format
@@ -819,7 +819,7 @@ var BACKFILL_CLI_COMMANDS = [
819
819
  },
820
820
  allowPositionals: false,
821
821
  run: async (input) => {
822
- const { backfillAiReferralPathsCommand } = await import("./backfill-ZSLOPGNJ.js");
822
+ const { backfillAiReferralPathsCommand } = await import("./backfill-6UMNMA5D.js");
823
823
  await backfillAiReferralPathsCommand({
824
824
  project: getString(input.values, "project"),
825
825
  format: input.format
@@ -831,7 +831,7 @@ var BACKFILL_CLI_COMMANDS = [
831
831
  usage: "canonry backfill snapshot-attribution <project> [--dry-run] [--format json]",
832
832
  supportsDryRun: true,
833
833
  run: async (input) => {
834
- const { backfillSnapshotAttributionCommand } = await import("./backfill-ZSLOPGNJ.js");
834
+ const { backfillSnapshotAttributionCommand } = await import("./backfill-6UMNMA5D.js");
835
835
  const usage = "canonry backfill snapshot-attribution <project> [--dry-run] [--format json]";
836
836
  const project3 = requireProject(input, "backfill snapshot-attribution", usage);
837
837
  await backfillSnapshotAttributionCommand({
@@ -850,7 +850,7 @@ var BACKFILL_CLI_COMMANDS = [
850
850
  allowPositionals: false,
851
851
  supportsDryRun: true,
852
852
  run: async (input) => {
853
- const { backfillTrafficClassificationCommand } = await import("./backfill-ZSLOPGNJ.js");
853
+ const { backfillTrafficClassificationCommand } = await import("./backfill-6UMNMA5D.js");
854
854
  await backfillTrafficClassificationCommand({
855
855
  project: getString(input.values, "project"),
856
856
  dryRun: input.dryRun,
@@ -1494,7 +1494,7 @@ var DASHBOARD_CLI_COMMANDS = [
1494
1494
  usage: "canonry dashboard reset-password [--format json]",
1495
1495
  help: "Clears the dashboard password from config.yaml, so the dashboard asks for a new one after a restart.\nLocal only: it edits the config file under CANONRY_CONFIG_DIR and does not call the server.",
1496
1496
  run: async (input) => {
1497
- const { resetDashboardPassword } = await import("./dashboard-BC4XZVJW.js");
1497
+ const { resetDashboardPassword } = await import("./dashboard-A2GTXYCN.js");
1498
1498
  await resetDashboardPassword({ format: input.format });
1499
1499
  }
1500
1500
  },
@@ -7161,7 +7161,7 @@ var SYSTEM_CLI_COMMANDS = [
7161
7161
  options: { access: stringOption() },
7162
7162
  run: async (input) => {
7163
7163
  if (input.positionals.length > 1) throw usageError("Expected at most one command group");
7164
- const [{ printCliCatalog }, { REGISTERED_CLI_COMMANDS: REGISTERED_CLI_COMMANDS2 }] = await Promise.all([import("./cli-catalog-MWRBP7AQ.js"), import("./cli-commands-WPTOQUHN.js")]);
7164
+ const [{ printCliCatalog }, { REGISTERED_CLI_COMMANDS: REGISTERED_CLI_COMMANDS2 }] = await Promise.all([import("./cli-catalog-MWRBP7AQ.js"), import("./cli-commands-WCKKUVFG.js")]);
7165
7165
  printCliCatalog(REGISTERED_CLI_COMMANDS2, input.format, input.positionals[0], getString(input.values, "access"));
7166
7166
  }
7167
7167
  },
@@ -7210,7 +7210,7 @@ var SYSTEM_CLI_COMMANDS = [
7210
7210
  },
7211
7211
  allowPositionals: false,
7212
7212
  run: async (input) => {
7213
- const { initCommand } = await import("./init-OCKHQ7IL.js");
7213
+ const { initCommand } = await import("./init-T7KF667H.js");
7214
7214
  await initCommand({
7215
7215
  force: getBoolean(input.values, "force"),
7216
7216
  ref: getString(input.values, "ref"),
@@ -7265,7 +7265,7 @@ var SYSTEM_CLI_COMMANDS = [
7265
7265
  allowPositionals: false,
7266
7266
  run: async (input) => {
7267
7267
  applyServerEnv(input.values);
7268
- const { serveCommand } = await import("./serve-MH7ZC44A.js");
7268
+ const { serveCommand } = await import("./serve-NHQ4J6IG.js");
7269
7269
  await serveCommand(input.format);
7270
7270
  }
7271
7271
  },
@@ -8657,8 +8657,8 @@ var AGENT_CLI_COMMANDS = [
8657
8657
  "timeout-ms": stringOption()
8658
8658
  },
8659
8659
  run: async (input) => {
8660
- const { coerceAgentProvider } = await import("./session-P6STOUZI.js");
8661
- const { AERO_TOOL_PROFILES, isAeroToolProfile } = await import("./tools-AJWV72XT.js");
8660
+ const { coerceAgentProvider } = await import("./session-L4CT3XZQ.js");
8661
+ const { AERO_TOOL_PROFILES, isAeroToolProfile } = await import("./tools-OIVQXP5C.js");
8662
8662
  const { agentAsk } = await import("./agent-ask-ATVWKFBN.js");
8663
8663
  const usage = `canonry agent ask <project> "<prompt>" [--provider ${AGENT_PROVIDER_IDS.join("|")}] [--model <id>] [--scope all|read-only] [--profile default|ads-operator] [--context <json>] [--conversation <id>] [--max-tool-calls <n>] [--timeout-ms <ms>] [--format json]`;
8664
8664
  const project3 = requireProject(input, "agent.ask", usage);
@@ -27,14 +27,14 @@ import {
27
27
  resolveConfiguredAgentProvider,
28
28
  resolveSessionProviderAndModel,
29
29
  setAeroSystemPrompt
30
- } from "./chunk-HL64C53O.js";
30
+ } from "./chunk-BYPNVDJE.js";
31
31
  import {
32
32
  AeroToolProfiles,
33
33
  AeroToolScopes,
34
34
  buildAeroStateTools,
35
35
  isAeroToolProfile,
36
36
  truncateToolResult
37
- } from "./chunk-NKJLQ6ED.js";
37
+ } from "./chunk-CD7WROGG.js";
38
38
  import {
39
39
  getGoogleAuthConfig,
40
40
  getGoogleConnection,
@@ -65,7 +65,7 @@ import {
65
65
  openrouterAdapter,
66
66
  perplexityAdapter,
67
67
  startTrafficReclassification
68
- } from "./chunk-FFPD6DWR.js";
68
+ } from "./chunk-KIUXAGME.js";
69
69
  import {
70
70
  classifyUsageSurface,
71
71
  createApiUsageTelemetry,
@@ -162,7 +162,7 @@ import {
162
162
  } from "./chunk-HGMYEDAQ.js";
163
163
  import {
164
164
  IntelligenceService
165
- } from "./chunk-VRDN5TH7.js";
165
+ } from "./chunk-FVA3QBUJ.js";
166
166
  import {
167
167
  computeCitedCompetitorDomains,
168
168
  determineCitationState
@@ -316,7 +316,7 @@ import {
316
316
  webhookResponseReason,
317
317
  webhookTargetRefusalReason,
318
318
  writeAuditLog
319
- } from "./chunk-7VPF373L.js";
319
+ } from "./chunk-RQMGGRIO.js";
320
320
  import {
321
321
  OperationalLogStore,
322
322
  SentimentIdempotencyConflict,
@@ -5980,7 +5980,7 @@ function nonBlank(value) {
5980
5980
  return trimmed ? trimmed : void 0;
5981
5981
  }
5982
5982
  function resolveBuildCommit(env = process.env) {
5983
- const embedded = true ? "f5d4612e23d2b1f0e5f46b217245359125c52a80" : void 0;
5983
+ const embedded = true ? "c9c5d088f29e5bd2401d84d2b77d8720e9360728" : void 0;
5984
5984
  return nonBlank(embedded) ?? nonBlank(env.CANONRY_COMMIT);
5985
5985
  }
5986
5986
  function resolveInstanceIdentity(env = process.env) {
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  REGISTERED_CLI_COMMANDS
3
- } from "./chunk-WQJCGMHW.js";
3
+ } from "./chunk-WOHQNWVO.js";
4
4
  import "./chunk-6GO5VVAC.js";
5
5
  import "./chunk-VJWDBFSL.js";
6
6
  import "./chunk-DVIZZYL5.js";
package/dist/cli.js CHANGED
@@ -1,12 +1,12 @@
1
1
  #!/usr/bin/env node --import tsx
2
2
  import {
3
3
  REGISTERED_CLI_COMMANDS
4
- } from "./chunk-WQJCGMHW.js";
4
+ } from "./chunk-WOHQNWVO.js";
5
5
  import "./chunk-6GO5VVAC.js";
6
6
  import {
7
7
  buildSetupState,
8
8
  runPendingServeHandoff
9
- } from "./chunk-VNQHCJXG.js";
9
+ } from "./chunk-NBZ7GLTP.js";
10
10
  import "./chunk-VJWDBFSL.js";
11
11
  import "./chunk-DVIZZYL5.js";
12
12
  import "./chunk-TSENU4GG.js";
@@ -7,7 +7,7 @@ import {
7
7
  } from "./chunk-HGMYEDAQ.js";
8
8
  import {
9
9
  anyUsersExist
10
- } from "./chunk-7VPF373L.js";
10
+ } from "./chunk-RQMGGRIO.js";
11
11
  import "./chunk-6TIJFZX5.js";
12
12
  import "./chunk-D4ABSOQG.js";
13
13
  import {
@@ -40,7 +40,7 @@ function parseDemoTrustedProxies(values) {
40
40
  async function demoCommand(options) {
41
41
  const { host, port } = parseDemoListenOptions(options);
42
42
  const trustProxy = parseDemoTrustedProxies(options.trustProxy);
43
- const { createDemoServer } = await import("./demo-server-YPDXH7HV.js");
43
+ const { createDemoServer } = await import("./demo-server-2EIJCN6D.js");
44
44
  const app = await createDemoServer({ trustProxy });
45
45
  let stopping = false;
46
46
  const stop = () => {
@@ -18,7 +18,7 @@ import "./chunk-HGMYEDAQ.js";
18
18
  import {
19
19
  HISTORY_WINDOW_RUNS,
20
20
  IntelligenceService
21
- } from "./chunk-VRDN5TH7.js";
21
+ } from "./chunk-FVA3QBUJ.js";
22
22
  import {
23
23
  determineCitationState
24
24
  } from "./chunk-QP6RYMZR.js";
@@ -26,7 +26,7 @@ import "./chunk-RIQXJDGZ.js";
26
26
  import {
27
27
  apiRoutes,
28
28
  assessConversionTrackingIntegrity
29
- } from "./chunk-7VPF373L.js";
29
+ } from "./chunk-RQMGGRIO.js";
30
30
  import "./chunk-6TIJFZX5.js";
31
31
  import "./chunk-D4ABSOQG.js";
32
32
  import {
package/dist/index.js CHANGED
@@ -3,14 +3,14 @@ import {
3
3
  createGoogleMarketingCredentialStore,
4
4
  createGoogleMarketingRuntime,
5
5
  createServer
6
- } from "./chunk-PL5T2LOA.js";
6
+ } from "./chunk-XJQNALKR.js";
7
7
  import "./chunk-M6OBSGWD.js";
8
- import "./chunk-HL64C53O.js";
9
- import "./chunk-NKJLQ6ED.js";
8
+ import "./chunk-BYPNVDJE.js";
9
+ import "./chunk-CD7WROGG.js";
10
10
  import "./chunk-ELCLGWUT.js";
11
11
  import "./chunk-XEBKF4N5.js";
12
12
  import "./chunk-YL3ZBKBV.js";
13
- import "./chunk-FFPD6DWR.js";
13
+ import "./chunk-KIUXAGME.js";
14
14
  import "./chunk-F2O75EG3.js";
15
15
  import "./chunk-TSENU4GG.js";
16
16
  import "./chunk-Z57QUHG6.js";
@@ -28,10 +28,10 @@ import "./chunk-GSQR574F.js";
28
28
  import "./chunk-SKXOS5YA.js";
29
29
  import "./chunk-AOJU5LKX.js";
30
30
  import "./chunk-HGMYEDAQ.js";
31
- import "./chunk-VRDN5TH7.js";
31
+ import "./chunk-FVA3QBUJ.js";
32
32
  import "./chunk-QP6RYMZR.js";
33
33
  import "./chunk-RIQXJDGZ.js";
34
- import "./chunk-7VPF373L.js";
34
+ import "./chunk-RQMGGRIO.js";
35
35
  import "./chunk-6TIJFZX5.js";
36
36
  import "./chunk-D4ABSOQG.js";
37
37
  import "./chunk-VDWTOMU4.js";
@@ -7,7 +7,7 @@ import {
7
7
  import {
8
8
  buildSetupState,
9
9
  queueServeHandoff
10
- } from "./chunk-VNQHCJXG.js";
10
+ } from "./chunk-NBZ7GLTP.js";
11
11
  import "./chunk-VJWDBFSL.js";
12
12
  import "./chunk-F2O75EG3.js";
13
13
  import "./chunk-Z57QUHG6.js";
@@ -1,10 +1,10 @@
1
1
  import {
2
2
  HISTORY_WINDOW_RUNS,
3
3
  IntelligenceService
4
- } from "./chunk-VRDN5TH7.js";
4
+ } from "./chunk-FVA3QBUJ.js";
5
5
  import "./chunk-QP6RYMZR.js";
6
6
  import "./chunk-RIQXJDGZ.js";
7
- import "./chunk-7VPF373L.js";
7
+ import "./chunk-RQMGGRIO.js";
8
8
  import "./chunk-6TIJFZX5.js";
9
9
  import "./chunk-D4ABSOQG.js";
10
10
  import "./chunk-VDWTOMU4.js";
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  backfillAiReferralPaths,
3
3
  backfillNormalizedPaths
4
- } from "./chunk-JJH55CAR.js";
4
+ } from "./chunk-I37MDUG5.js";
5
5
  import {
6
6
  operatorHttpUrl
7
7
  } from "./chunk-6GO5VVAC.js";
@@ -9,14 +9,14 @@ import {
9
9
  allowsKeylessFirstRunSetup,
10
10
  createServer,
11
11
  waitForServerRuntimeStartup
12
- } from "./chunk-PL5T2LOA.js";
12
+ } from "./chunk-XJQNALKR.js";
13
13
  import "./chunk-M6OBSGWD.js";
14
- import "./chunk-HL64C53O.js";
15
- import "./chunk-NKJLQ6ED.js";
14
+ import "./chunk-BYPNVDJE.js";
15
+ import "./chunk-CD7WROGG.js";
16
16
  import "./chunk-ELCLGWUT.js";
17
17
  import "./chunk-XEBKF4N5.js";
18
18
  import "./chunk-YL3ZBKBV.js";
19
- import "./chunk-FFPD6DWR.js";
19
+ import "./chunk-KIUXAGME.js";
20
20
  import {
21
21
  trackFeatureCompleted
22
22
  } from "./chunk-F2O75EG3.js";
@@ -57,13 +57,13 @@ import {
57
57
  CliError,
58
58
  isMachineFormat
59
59
  } from "./chunk-HGMYEDAQ.js";
60
- import "./chunk-VRDN5TH7.js";
60
+ import "./chunk-FVA3QBUJ.js";
61
61
  import "./chunk-QP6RYMZR.js";
62
62
  import "./chunk-RIQXJDGZ.js";
63
63
  import {
64
64
  refreshSnapshotMentionIdentity,
65
65
  snapshotsWithSentimentResults
66
- } from "./chunk-7VPF373L.js";
66
+ } from "./chunk-RQMGGRIO.js";
67
67
  import "./chunk-6TIJFZX5.js";
68
68
  import "./chunk-D4ABSOQG.js";
69
69
  import {
@@ -9,8 +9,8 @@ import {
9
9
  resolveAeroModel,
10
10
  resolveConfiguredAgentProvider,
11
11
  resolveSessionProviderAndModel
12
- } from "./chunk-HL64C53O.js";
13
- import "./chunk-NKJLQ6ED.js";
12
+ } from "./chunk-BYPNVDJE.js";
13
+ import "./chunk-CD7WROGG.js";
14
14
  import {
15
15
  resolveAeroSkillDir
16
16
  } from "./chunk-MTW37GXF.js";
@@ -26,7 +26,7 @@ import "./chunk-SKXOS5YA.js";
26
26
  import "./chunk-AOJU5LKX.js";
27
27
  import "./chunk-HGMYEDAQ.js";
28
28
  import "./chunk-RIQXJDGZ.js";
29
- import "./chunk-7VPF373L.js";
29
+ import "./chunk-RQMGGRIO.js";
30
30
  import "./chunk-6TIJFZX5.js";
31
31
  import "./chunk-D4ABSOQG.js";
32
32
  import "./chunk-VDWTOMU4.js";
@@ -11,7 +11,7 @@ import {
11
11
  buildAllTools,
12
12
  buildReadTools,
13
13
  isAeroToolProfile
14
- } from "./chunk-NKJLQ6ED.js";
14
+ } from "./chunk-CD7WROGG.js";
15
15
  import "./chunk-RXWISYNN.js";
16
16
  import "./chunk-PNVI2UYZ.js";
17
17
  import "./chunk-BUTOZPE7.js";
@@ -19,7 +19,7 @@ import "./chunk-GSQR574F.js";
19
19
  import "./chunk-SKXOS5YA.js";
20
20
  import "./chunk-AOJU5LKX.js";
21
21
  import "./chunk-HGMYEDAQ.js";
22
- import "./chunk-7VPF373L.js";
22
+ import "./chunk-RQMGGRIO.js";
23
23
  import "./chunk-6TIJFZX5.js";
24
24
  import "./chunk-D4ABSOQG.js";
25
25
  import "./chunk-VDWTOMU4.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@canonry/canonry",
3
- "version": "7.97.0",
3
+ "version": "7.97.2",
4
4
  "type": "module",
5
5
  "description": "Self-hosted AI visibility (AEO) platform: track how ChatGPT, Claude, Gemini, and Perplexity cite your domain, join it with Search Console, GA4, server-side traffic, and paid media, and fix what you find through agent tools (CLI, REST, MCP). Local SQLite.",
6
6
  "keywords": [