@canonry/canonry 7.91.0 → 7.91.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.
package/README.md CHANGED
@@ -1,15 +1,94 @@
1
- # Canonry <img src="https://raw.githubusercontent.com/Canonry/canonry/main/apps/web/public/favicon-32.png" alt="Canonry canary icon" width="24" />
1
+ <h1 align="center">
2
+ <a href="https://canonry.ai"><img src="https://raw.githubusercontent.com/Canonry/canonry/main/apps/web/public/apple-touch-icon.png" alt="Canonry" width="64" valign="middle" /></a> Canonry
3
+ </h1>
2
4
 
3
- [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](./LICENSE)
4
- [![npm version](https://img.shields.io/npm/v/@canonry/canonry)](https://www.npmjs.com/package/@canonry/canonry)
5
- [![Discord](https://img.shields.io/badge/Discord-Join-5865F2?logo=discord&logoColor=white)](https://discord.gg/8K9yY7GywJ)
6
- [![Twitter](https://img.shields.io/badge/Twitter-Follow-000000?logo=x&logoColor=white)](https://x.com/canonry_ai)
5
+ <p align="center">
6
+ <a href="https://www.npmjs.com/package/@canonry/canonry"><img src="https://img.shields.io/npm/v/@canonry/canonry?style=flat&amp;label=npm&amp;color=D93F45" alt="npm version" /></a>
7
+ <a href="https://www.npmjs.com/package/@canonry/canonry"><img src="https://img.shields.io/npm/dt/@canonry/canonry?style=flat&amp;label=downloads&amp;color=D93F45" alt="Total npm downloads" /></a>
8
+ <a href="./LICENSE"><img src="https://img.shields.io/badge/license-MIT-D93F45?style=flat" alt="License: MIT" /></a>
9
+ <a href="https://discord.gg/8K9yY7GywJ"><img src="https://img.shields.io/badge/Discord-5865F2?logo=discord&amp;logoColor=white" alt="Join the Canonry Discord" /></a>
10
+ <a href="https://x.com/canonry_ai"><img src="https://img.shields.io/badge/X-000000?logo=x&amp;logoColor=white" alt="Follow Canonry on X" /></a>
11
+ <img src="https://img.shields.io/badge/API%20%7C%20CLI%20%7C%20MCP%20%7C%20Web-4493F8?style=flat-square" alt="Interfaces: REST API, CLI, MCP, and web dashboard" />
12
+ </p>
13
+
14
+ <p align="center">
15
+ <strong>The agent-first AEO operating platform.</strong><br/>
16
+ Track mentions and citations across ChatGPT, Claude, Gemini, Meta Muse, and more. Join them with Search Console, GA4, ads, AI crawler traffic, site audits, and SEO data. Then let your agent create content, publish fixes, manage ChatGPT ads, get pages indexed, and measure what changed.<br/>
17
+ <sub>Open source · Self-hosted · Bring your own keys</sub>
18
+ </p>
19
+
20
+ <h3 align="center"><a href="https://custom-demo.canonry.ai/projects/summit-roofing"><ins>Try the live demo</ins></a> &nbsp;·&nbsp; <a href="#quick-start"><ins>Quick start</ins></a></h3>
21
+
22
+ <p align="center">
23
+ <a href="https://custom-demo.canonry.ai/projects/summit-roofing"><picture><source media="(max-width: 600px)" srcset="https://raw.githubusercontent.com/Canonry/canonry/main/docs/images/readme/hero-mobile.png" /><img src="https://raw.githubusercontent.com/Canonry/canonry/main/docs/images/readme/hero.png" alt="Canonry dashboard: AI answers over time, with the share of non-brand answers that mention the brand for Claude, Gemini, and OpenAI, with sample data" width="100%" /></picture></a>
24
+ </p>
25
+
26
+ <a id="explore-the-evidence"></a>
27
+ <a id="add-ai-visibility-when-you-need-it"></a>
28
+
29
+ ## Features
30
+
31
+ ### Built for Agents
32
+
33
+ Everything runs on one REST API. The dashboard, CLI, MCP server, and plugins all call it, so your agent can read and do everything you see.
34
+
35
+ - **REST API:** every dashboard number has a typed endpoint under `/api/v1`. The full OpenAPI spec is at `GET /api/v1/openapi.json`. [API →](#self-hosting-and-api)
36
+ - **CLI:** the same calls as `cnry <command> --format json`, for scripts and shell agents. [CLI →](skills/canonry/references/canonry-cli.md)
37
+ - **MCP and plugins:** plugins for Claude Code and Codex, or a hosted MCP server for ChatGPT and Claude Desktop. [MCP →](docs/mcp.md) · [Plugin →](docs/plugins.md)
38
+
39
+ ### AI Visibility
40
+
41
+ Track brand mentions and citations by query and answer engine. See where competitors win, then open the exact answer and sources behind each result. [Docs →](docs/query-visibility.md)
42
+
43
+ <a href="https://custom-demo.canonry.ai/projects/summit-roofing"><picture><source media="(max-width: 600px)" srcset="https://raw.githubusercontent.com/Canonry/canonry/main/docs/images/readme/ai-visibility-mobile.png" /><img src="https://raw.githubusercontent.com/Canonry/canonry/main/docs/images/readme/ai-visibility.png" alt="Where competitors are winning: mention share against two competitors, mention and citation gaps, and mentioned and cited counts by engine, with sample data" width="100%" /></picture></a>
44
+
45
+ ### Server-Side AI Traffic
46
+
47
+ See what AI agents actually do on your site, from your server logs: which pages GPTBot, ClaudeBot, Meta AI, and Grok crawl, which pages ChatGPT, Claude, and Meta AI open for users, and who clicks through. [Docs →](skills/canonry/references/server-side-traffic.md)
48
+
49
+ <a href="skills/canonry/references/server-side-traffic.md"><picture><source media="(max-width: 600px)" srcset="https://raw.githubusercontent.com/Canonry/canonry/main/docs/images/readme/traffic-mobile.png" /><img src="https://raw.githubusercontent.com/Canonry/canonry/main/docs/images/readme/traffic.png" alt="Server traffic for the last 24 hours: 105 AI crawler visits, 35 AI user fetches, and 46 AI referral sessions, with an hourly chart, with sample data" width="100%" /></picture></a>
50
+
51
+ ### Site Health
52
+
53
+ Crawl your site, score each page for AI readiness, and map the internal links between pages. Each finding lists the pages it affects. [Docs →](skills/canonry/references/canonry-cli.md#site-health-technical-aeo-compatibility)
54
+
55
+ <a href="skills/canonry/references/canonry-cli.md#site-health-technical-aeo-compatibility"><picture><source media="(max-width: 600px)" srcset="https://raw.githubusercontent.com/Canonry/canonry/main/docs/images/readme/site-health-mobile.png" /><img src="https://raw.githubusercontent.com/Canonry/canonry/main/docs/images/readme/site-health.png" alt="Site map of 205 crawled pages and the links between them, beside a list of site sections, with sample data" width="100%" /></picture></a>
56
+
57
+ <a id="seo-data"></a>
58
+
59
+ ### SEO Research
60
+
61
+ Keyword volume, difficulty, organic rankings, and search gaps against competitors, powered by DataForSEO Labs. [Docs →](docs/seo-data.md)
62
+
63
+ <a href="docs/seo-data.md"><picture><source media="(max-width: 600px)" srcset="https://raw.githubusercontent.com/Canonry/canonry/main/docs/images/readme/seo-mobile.png" /><img src="https://raw.githubusercontent.com/Canonry/canonry/main/docs/images/readme/seo.png" alt="SEO page with ranked searches, top-10 count, estimated organic traffic, and a table of positions, volume, and difficulty, with sample data" width="100%" /></picture></a>
64
+
65
+ ### Ads
66
+
67
+ Let your agent run ChatGPT Ads: sync campaigns and daily results, create and edit campaigns, and switch them on only after you approve. Track Google Ads spend and conversions, and check each conversion's setup across Google Ads and Tag Manager. Paid results stay separate from organic mentions and citations. [ChatGPT Ads →](skills/canonry/references/canonry-cli.md#openai-ads-chatgpt-ads) · [Google Ads →](docs/google-marketing.md)
7
68
 
8
- Canonry is an **agent-first (CLI, MCP, API), open-source AEO operating platform with a comprehensive web UI.** Track AI visibility over time, investigate changes across search and traffic, and measure progress after you or your agent acts.
69
+ <a href="docs/google-marketing.md"><picture><source media="(max-width: 600px)" srcset="https://raw.githubusercontent.com/Canonry/canonry/main/docs/images/readme/ads-mobile.png" /><img src="https://raw.githubusercontent.com/Canonry/canonry/main/docs/images/readme/ads.png" alt="Google Ads performance: spend, conversions, cost per conversion, a daily chart, and campaign results, with sample data" width="100%" /></picture></a>
9
70
 
10
- **Self-hosted, using SQLite, with your own (BYOK) provider keys.** The web UI and your agent see the same evidence.
71
+ <a id="compare-competitors-and-measure-complex-portfolios"></a>
72
+ <a id="act-on-the-evidence"></a>
73
+
74
+ **Also in the box:**
75
+
76
+ - **[Aero](skills/aero/SKILL.md)** — A built-in analyst in the dashboard that reads your evidence and explains what changed.
77
+ - **[Portfolios](skills/canonry/references/canonry-cli.md#target-measurement-plans)** — Versioned measurement plans for locations, products, or site sections. Branded and non-brand queries stay separate.
78
+ - **[Competitor landscape](docs/competitor-landscape.md)** — Mention share, mentions, and citations for you and your competitors over time.
79
+ - **[Query discovery and research](skills/canonry/references/canonry-cli.md#discovery-tracked-basket-expansion)** — Find new queries to track, or run one-off research without changing what you track.
80
+ - **[Content engine](skills/canonry/references/canonry-cli.md#content-target-dismissals)** — Finds content gaps and the pages to write or improve next, so your agent can draft them and publish to WordPress for review.
81
+ - **[Publish and index](skills/canonry/references/indexing.md)** — WordPress drafts, JSON-LD, and sitemap and URL submissions to Google and Bing.
82
+ - **[Schedules and webhooks](skills/canonry/references/canonry-cli.md#scheduling--notifications)** — Rerun checks on a schedule and send alerts to Discord, Slack, or your systems.
83
+ - **[Backlinks](skills/canonry/references/canonry-cli.md#backlinks-common-crawl)** — Common Crawl link data, queried locally with DuckDB.
84
+ - **[Sentiment](docs/sentiment.md)** — Experimental, off by default. Rates branded answers as favorable, mixed, or unfavorable.
85
+ - **And more** — browse the [documentation index](docs/README.md).
86
+
87
+ **An example job for your connected agent:**
88
+
89
+ > Find where competitors get cited and we don't. Use search data and the site audit to prepare a pull request or WordPress draft for review. After it ships, rerun checks and report what changed.
11
90
 
12
- [Live UI Demo](https://custom-demo.canonry.ai/projects/summit-roofing) · [Quick start](#quick-start) · [Evidence](#explore-the-evidence) · [Actions](#act-on-the-evidence) · [Integrations](#integrations) · [Docs](#documentation) · [Support](#support)
91
+ ## How it works
13
92
 
14
93
  <p align="center">
15
94
  <a href="https://raw.githubusercontent.com/Canonry/canonry/main/docs/images/measure-act.svg">
@@ -17,11 +96,65 @@ Canonry is an **agent-first (CLI, MCP, API), open-source AEO operating platform
17
96
  </a>
18
97
  </p>
19
98
 
99
+ ---
100
+
101
+ ## Supported Engines
102
+
103
+ Compare direct AI engines, OpenRouter models, and search answers from Exa and Parallel. Each keeps its own results and history.
104
+
105
+ <p>
106
+ <a href="https://platform.openai.com/api-keys"><kbd><img src="https://www.google.com/s2/favicons?domain=openai.com&amp;sz=64" alt="OpenAI logo" width="16" valign="middle" /> ChatGPT</kbd></a> &nbsp;
107
+ <a href="https://console.anthropic.com/settings/keys"><kbd><img src="https://www.google.com/s2/favicons?domain=claude.ai&amp;sz=64" alt="Claude logo" width="16" valign="middle" /> Claude</kbd></a> &nbsp;
108
+ <a href="https://aistudio.google.com/apikey"><kbd><img src="https://www.google.com/s2/favicons?domain=gemini.google.com&amp;sz=64" alt="Gemini logo" width="16" valign="middle" /> Gemini</kbd></a> &nbsp;
109
+ <a href="https://www.perplexity.ai/settings/api"><kbd><img src="https://www.google.com/s2/favicons?domain=perplexity.ai&amp;sz=64" alt="Perplexity logo" width="16" valign="middle" /> Perplexity</kbd></a> &nbsp;
110
+ <a href="https://dev.meta.ai/"><kbd><img src="https://www.google.com/s2/favicons?domain=meta.ai&amp;sz=64" alt="Meta logo" width="16" valign="middle" /> Meta (Muse)</kbd></a> &nbsp;
111
+ <a href="docs/providers/openrouter.md"><kbd><img src="https://www.google.com/s2/favicons?domain=openrouter.ai&amp;sz=64" alt="OpenRouter logo" width="16" valign="middle" /> OpenRouter</kbd></a> &nbsp;
112
+ <a href="docs/providers/answer-services/exa.md"><kbd><img src="https://www.google.com/s2/favicons?domain=exa.ai&amp;sz=64" alt="Exa logo" width="16" valign="middle" /> Exa</kbd></a> &nbsp;
113
+ <a href="docs/providers/answer-services/parallel.md"><kbd><img src="https://www.google.com/s2/favicons?domain=parallel.ai&amp;sz=64" alt="Parallel logo" width="16" valign="middle" /> Parallel</kbd></a> &nbsp;
114
+ <kbd>+ any OpenAI-compatible local model</kbd>
115
+ </p>
116
+
117
+ **Works with your agent:**
118
+
119
+ <p>
120
+ <a href="docs/plugins.md#install-for-claude-code"><kbd><img src="https://www.google.com/s2/favicons?domain=claude.ai&amp;sz=64" alt="Claude Code logo" width="16" valign="middle" /> Claude Code</kbd></a> &nbsp;
121
+ <a href="docs/plugins.md#install-for-codex"><kbd><img src="https://www.google.com/s2/favicons?domain=openai.com&amp;sz=64" alt="Codex logo" width="16" valign="middle" /> Codex</kbd></a> &nbsp;
122
+ <a href="docs/mcp.md"><kbd><img src="https://www.google.com/s2/favicons?domain=chatgpt.com&amp;sz=64" alt="ChatGPT logo" width="16" valign="middle" /> ChatGPT</kbd></a> &nbsp;
123
+ <a href="docs/mcp.md"><kbd><img src="https://www.google.com/s2/favicons?domain=claude.ai&amp;sz=64" alt="Claude Desktop logo" width="16" valign="middle" /> Claude Desktop</kbd></a> &nbsp;
124
+ <kbd>+ any MCP client or shell-capable agent</kbd>
125
+ </p>
126
+
127
+ <a id="built-in-integrations-and-workflows"></a>
128
+
129
+ ## Integrations
130
+
131
+ Connect the sources you use. Each one adds evidence or tools to the same project.
132
+
133
+ <p>
134
+ <a href="docs/google-search-console-setup.md"><kbd><img src="https://www.google.com/s2/favicons?domain=search.google.com&amp;sz=64" alt="Google Search Console logo" width="16" valign="middle" /> Search Console</kbd></a> &nbsp;
135
+ <a href="docs/bing-webmaster-setup.md"><kbd><img src="https://www.google.com/s2/favicons?domain=bing.com&amp;sz=64" alt="Bing logo" width="16" valign="middle" /> Bing Webmaster Tools</kbd></a> &nbsp;
136
+ <a href="docs/google-analytics-setup.md"><kbd><img src="https://www.google.com/s2/favicons?domain=analytics.google.com&amp;sz=64" alt="Google Analytics logo" width="16" valign="middle" /> Google Analytics 4</kbd></a> &nbsp;
137
+ <a href="skills/canonry/references/google-business-profile.md"><kbd><img src="https://www.google.com/s2/favicons?domain=business.google.com&amp;sz=64" alt="Google Business Profile logo" width="16" valign="middle" /> Business Profile</kbd></a> &nbsp;
138
+ <a href="docs/google-marketing.md"><kbd><img src="https://www.google.com/s2/favicons?domain=ads.google.com&amp;sz=64" alt="Google Ads logo" width="16" valign="middle" /> Google Ads</kbd></a> &nbsp;
139
+ <a href="docs/google-marketing.md"><kbd><img src="https://www.google.com/s2/favicons?domain=tagmanager.google.com&amp;sz=64" alt="Google Tag Manager logo" width="16" valign="middle" /> Tag Manager</kbd></a> &nbsp;
140
+ <a href="docs/cloudflare-traffic-setup.md"><kbd><img src="https://www.google.com/s2/favicons?domain=cloudflare.com&amp;sz=64" alt="Cloudflare logo" width="16" valign="middle" /> Cloudflare</kbd></a> &nbsp;
141
+ <a href="skills/canonry/references/server-side-traffic.md"><kbd><img src="https://www.google.com/s2/favicons?domain=vercel.com&amp;sz=64" alt="Vercel logo" width="16" valign="middle" /> Vercel</kbd></a> &nbsp;
142
+ <a href="skills/canonry/references/server-side-traffic.md"><kbd><img src="https://www.google.com/s2/favicons?domain=cloud.google.com&amp;sz=64" alt="Google Cloud logo" width="16" valign="middle" /> Cloud Run</kbd></a> &nbsp;
143
+ <a href="docs/wordpress-setup.md"><kbd><img src="https://www.google.com/s2/favicons?domain=wordpress.org&amp;sz=64" alt="WordPress logo" width="16" valign="middle" /> WordPress</kbd></a> &nbsp;
144
+ <a href="docs/seo-data.md"><kbd><img src="https://www.google.com/s2/favicons?domain=dataforseo.com&amp;sz=64" alt="DataForSEO logo" width="16" valign="middle" /> DataForSEO</kbd></a> &nbsp;
145
+ <a href="skills/canonry/references/canonry-cli.md#backlinks-common-crawl"><kbd><img src="https://www.google.com/s2/favicons?domain=commoncrawl.org&amp;sz=64" alt="Common Crawl logo" width="16" valign="middle" /> Common Crawl</kbd></a> &nbsp;
146
+ <a href="skills/canonry/references/canonry-cli.md#openai-ads-chatgpt-ads"><kbd><img src="https://www.google.com/s2/favicons?domain=chatgpt.com&amp;sz=64" alt="ChatGPT logo" width="16" valign="middle" /> ChatGPT Ads</kbd></a>
147
+ </p>
148
+
149
+ ---
150
+
20
151
  ## Quick start
21
152
 
22
153
  <a id="or-use-any-shell-capable-coding-agent"></a>
23
154
 
24
- ### Start with your agent
155
+ ### With your agent
156
+
157
+ Paste this into Claude Code, Codex, or any shell-capable coding agent.
25
158
 
26
159
  <details>
27
160
  <summary>Copy the first-time setup request</summary>
@@ -48,37 +181,31 @@ Pick one path and stay on it. Use connected Canonry tools (plugin or MCP) only i
48
181
 
49
182
  </details>
50
183
 
51
- ### Or Use Official Claude and Codex Plugins
52
-
53
- Connect the [Agent Plugin](docs/plugins.md) or [MCP adapter](docs/mcp.md) to your own agent.
184
+ ### With the plugin
54
185
 
55
- <a id="get-a-page-health-baseline"></a>
56
-
57
- ### Or start it locally yourself
58
-
59
- 1. Install Canonry.
60
-
61
- ```bash
62
- npm install -g @canonry/canonry
63
- ```
64
-
65
- If you previously installed `@ainyc/canonry`, run `npm uninstall -g @ainyc/canonry` first to release the shared command names. Existing configuration and data in `~/.canonry` stay in place. New releases are published only under `@canonry`.
186
+ ```bash
187
+ # Claude Code
188
+ claude plugin marketplace add Canonry/canonry
189
+ claude plugin install canonry@canonry
66
190
 
67
- 2. Initialize Canonry.
191
+ # Codex
192
+ codex plugin marketplace add Canonry/canonry
193
+ codex plugin add canonry@canonry
194
+ ```
68
195
 
69
- ```bash
70
- cnry bootstrap
71
- ```
196
+ Or connect the [MCP adapter](docs/mcp.md) to any MCP client. Full steps: [Agent Plugin guide](docs/plugins.md).
72
197
 
73
- 3. Start Canonry.
198
+ <a id="get-a-page-health-baseline"></a>
74
199
 
75
- ```bash
76
- cnry serve
77
- ```
200
+ ### On your own
78
201
 
79
- 4. Open [http://127.0.0.1:4100/setup](http://127.0.0.1:4100/setup) and follow the setup to scan your site.
202
+ ```bash
203
+ npm install -g @canonry/canonry
204
+ cnry bootstrap
205
+ cnry serve
206
+ ```
80
207
 
81
- The crawl saves a Page Health baseline. AI Visibility is optional and has a separate setup.
208
+ Then open [http://127.0.0.1:4100/setup](http://127.0.0.1:4100/setup) and follow the setup to scan your site. The crawl saves a Page Health baseline. AI Visibility is optional and has a separate setup.
82
209
 
83
210
  <details>
84
211
  <summary>Scan and read results from the terminal</summary>
@@ -102,27 +229,6 @@ If the scan fails or is cancelled, read the error with `cnry run show <run-id> -
102
229
 
103
230
  </details>
104
231
 
105
- ## Explore the evidence
106
-
107
- Your agent and dashboard use the same project API. The dashboard makes trends, exact answers, and site findings available for human review.
108
-
109
- <a id="add-ai-visibility-when-you-need-it"></a>
110
-
111
- ### AI visibility
112
-
113
- Track brand mentions and citations over time, by query and answer engine. Find answers that cite competitors but omit your site.
114
-
115
- Compare direct AI engines, OpenRouter models, and search answers from Exa and Parallel.
116
-
117
- ![Canonry AI Visibility mention share trend across answer engines](https://raw.githubusercontent.com/Canonry/canonry/main/docs/images/ai-visibility-trend.png)
118
-
119
- *Track your share of answer-engine brand mentions over time.*
120
-
121
- ![Canonry AI Visibility citation map across queries and answer engines](https://raw.githubusercontent.com/Canonry/canonry/main/docs/images/ai-visibility-diagnostics.png)
122
-
123
- The citation map shows mention and citation coverage across queries and engines.
124
- [Rank cited domains and pages](skills/canonry/references/canonry-cli.md#cited-source-rankings-cnry-sources), then inspect the exact answers and URLs behind each result.
125
-
126
232
  <details>
127
233
  <summary>Configure a provider and run visibility checks</summary>
128
234
 
@@ -181,67 +287,19 @@ For a configured portfolio destination, select one `--market <key>` or `--proper
181
287
 
182
288
  </details>
183
289
 
184
- <a id="compare-competitors-and-measure-complex-portfolios"></a>
185
-
186
- ### Search, traffic, and site health
187
-
188
- Investigate visibility changes with evidence from search and local performance, crawler visits, AI page fetches, referrals, and conversions.
189
- Site audits show technical findings alongside that evidence.
190
-
191
- ![Canonry Site Map graph](https://raw.githubusercontent.com/Canonry/canonry/main/docs/images/dashboard.png)
192
-
193
- *Map crawlable pages and the internal links that connect them.*
194
-
195
- <a id="seo-data"></a>
196
-
197
- ### SEO data with DataForSEO
198
-
199
- Use **DataForSEO Labs** for Google keyword research, organic rankings, and domain comparisons.
200
- Explore search volume, difficulty, CPC, ranking URLs, and estimated traffic through the dashboard, CLI, MCP, and API.
201
-
202
- [Configure DataForSEO](docs/seo-data.md).
203
-
204
- ![Canonry DataForSEO integration showing domain metrics and ranked keywords](docs/images/seo-data-phase-one/desktop.jpg)
205
-
206
- *SEO dashboard with sample data: organic keyword totals, estimated traffic, and ranked keywords.*
207
-
208
- ### Portfolios and competitors
209
-
210
- Use [versioned measurement plans](docs/mcp.md#tool-surface) for portfolios of locations, products, or site sections.
211
-
212
- - **Properties:** Assign queries, engines, models, and locations to each property. Keep branded and non-brand coverage separate.
213
- - **Market groups:** Organize overlapping sets of properties, each with its own competitors.
214
- - **Comparisons:** Compare properties, groups, engines, and locations. Open the exact answers and cited URLs behind each result.
215
-
216
- ## Act on the evidence
217
-
218
- Your agent coordinates the work through Canonry and its own tools.
219
-
220
- - **Improve the site:** Combine your agent's coding tools with Canonry's content, [WordPress publishing](docs/wordpress-setup.md), JSON-LD, and [indexing workflows](skills/canonry/references/indexing.md).
221
- - **Measure after changes:** Configure [independent schedules](skills/canonry/references/canonry-cli.md#scheduling--notifications) for data syncs and checks. Compare new results with earlier evidence.
222
- - **Export and follow up:** Read [AI visibility evidence](docs/report-retirement.md) and [traffic analytics](docs/report-retirement.md). Send [webhook alerts](skills/canonry/references/canonry-cli.md#agent) to Discord, Slack, or your systems.
223
-
224
- **An example job for your connected agent:**
225
-
226
- > Find where competitors get cited and we don't. Use search data and the site audit to prepare a pull request or WordPress draft for review. After it ships, rerun checks and report what changed.
227
-
228
- <a id="built-in-integrations-and-workflows"></a>
229
-
230
- ## Integrations
290
+ <a id="if-you-get-stuck"></a>
231
291
 
232
- Connect the sources you use. Each integration adds evidence or tools to the same project workflow.
292
+ <details>
293
+ <summary>Troubleshoot installation, scans, and visibility results</summary>
233
294
 
234
- | Area | Supported integrations |
295
+ | Problem | Next step |
235
296
  |---|---|
236
- | **AI answers** | ChatGPT · Claude · Gemini · Meta (Muse) · Perplexity · OpenAI-compatible local models |
237
- | **Search and local** | [Google Search Console](docs/google-search-console-setup.md) · [Bing Webmaster Tools](docs/bing-webmaster-setup.md) · [Google Business Profile](skills/canonry/references/google-business-profile.md) |
238
- | **SEO research** | **[DataForSEO Labs](docs/seo-data.md)**: keyword metrics, ranked keywords, and domain comparison |
239
- | **Analytics** | [Google Analytics 4](docs/google-analytics-setup.md) |
240
- | **Conversion measurement** | [Google Ads + Google Tag Manager](docs/google-marketing.md): read-only snapshots and declared conversion contracts |
241
- | **Server traffic** | [Cloudflare · Vercel · Cloud Run · WordPress](skills/canonry/references/server-side-traffic.md) |
242
- | **Backlinks** | [Common Crawl](skills/canonry/references/canonry-cli.md#backlinks-common-crawl) hyperlink releases, queried locally with DuckDB |
243
- | **Publishing and indexing** | [WordPress](docs/wordpress-setup.md) · JSON-LD · [sitemap and URL submissions](skills/canonry/references/indexing.md) |
244
- | **ChatGPT Ads** | [Campaign measurement, paused campaign editing, approved activation, and operation reconciliation](docs/mcp.md#tool-surface) |
297
+ | Site scan is still active | Read exact counters with `cnry technical-aeo progress <project> --run-id <id> --format json`. |
298
+ | Site scan failed | Read the error with `cnry run show <run-id> --format json`. Read the last phase and counters with the progress command. |
299
+ | No visibility results | Inspect existing work with `cnry runs <project> --format json`, then `cnry run show <run-id> --format json`. This does not start another paid run. |
300
+ | `npm install` fails on `node-gyp` | Install build tools for `better-sqlite3` ([guide](https://github.com/WiseLibs/better-sqlite3/blob/master/docs/troubleshooting.md)). |
301
+
302
+ </details>
245
303
 
246
304
  <a id="deployment-and-trust-boundary"></a>
247
305
  <a id="technical-surface"></a>
@@ -263,23 +321,18 @@ See the [deployment guide](docs/deployment.md) for reverse proxies, daemon mode,
263
321
  - **Install standalone agent skills:** `cnry skills install` ([guide](skills/canonry/SKILL.md))
264
322
  - **Browse all guides:** [Documentation index](docs/README.md)
265
323
 
266
- <a id="if-you-get-stuck"></a>
324
+ ---
267
325
 
268
- <details>
269
- <summary>Troubleshoot installation, scans, and visibility results</summary>
326
+ <a id="support"></a>
270
327
 
271
- | Problem | Next step |
272
- |---|---|
273
- | Site scan is still active | Read exact counters with `cnry technical-aeo progress <project> --run-id <id> --format json`. |
274
- | Site scan failed | Read the error with `cnry run show <run-id> --format json`. Read the last phase and counters with the progress command. |
275
- | No visibility results | Inspect existing work with `cnry runs <project> --format json`, then `cnry run show <run-id> --format json`. This does not start another paid run. |
276
- | `npm install` fails on `node-gyp` | Install build tools for `better-sqlite3` ([guide](https://github.com/WiseLibs/better-sqlite3/blob/master/docs/troubleshooting.md)). |
328
+ ## Community &amp; Support
277
329
 
278
- </details>
279
-
280
- ## Support
330
+ - **Discord:** Join the community on **[Discord](https://discord.gg/8K9yY7GywJ)** for help and questions.
331
+ - **Twitter / X:** Follow **[@canonry_ai](https://x.com/canonry_ai)** for updates.
332
+ - **Feedback &amp; Ideas:** Missing something? [Open an issue](https://github.com/Canonry/canonry/issues).
333
+ - **Show Support:** [Star](https://github.com/Canonry/canonry) this repo to follow along.
281
334
 
282
- Join the [Canonry Discord](https://discord.gg/8K9yY7GywJ) for support and questions about Canonry.
335
+ ---
283
336
 
284
337
  ## Contributing
285
338
 
@@ -291,6 +344,10 @@ pnpm install
291
344
  For local agent work, run tests only after changes are finalized and ready for push or review.
292
345
  `pnpm verify` is optional locally. See [CONTRIBUTING.md](./CONTRIBUTING.md) and the [testing guide](docs/testing.md).
293
346
 
347
+ <a href="https://github.com/Canonry/canonry/graphs/contributors">
348
+ <img src="https://contrib.rocks/image?repo=Canonry/canonry" alt="Canonry contributors" />
349
+ </a>
350
+
294
351
  ## License
295
352
 
296
353
  [MIT](./LICENSE), starting with Canonry 5.0.0. Use, modify, self-host, redistribute, and build commercial products with Canonry. Keep the copyright and permission notice with copies or substantial portions of the software.
@@ -10,8 +10,8 @@ import {
10
10
  backfillSnapshotAttributionCommand,
11
11
  backfillTrafficClassificationCommand,
12
12
  replayQueryAuditLog
13
- } from "./chunk-6Y4EVLV2.js";
14
- import "./chunk-N7MHVCML.js";
13
+ } from "./chunk-3MIZP4IB.js";
14
+ import "./chunk-PAXP5KZC.js";
15
15
  import "./chunk-YVY23HNW.js";
16
16
  import "./chunk-HGMYEDAQ.js";
17
17
  import "./chunk-P4MNYMJJ.js";
@@ -19,7 +19,7 @@ import "./chunk-SYOQULRL.js";
19
19
  import {
20
20
  backfillProjectAnswerMentions,
21
21
  backfillProjectAnswerMentionsInChunks
22
- } from "./chunk-WEDOXGGI.js";
22
+ } from "./chunk-42OW42AR.js";
23
23
  import "./chunk-NAPFULBT.js";
24
24
  import "./chunk-3HNHOS6O.js";
25
25
  import "./chunk-C3BSCGUH.js";
@@ -8,7 +8,7 @@ import {
8
8
  reparseStoredResult4,
9
9
  reparseStoredResult5,
10
10
  resolveStoredApiResponse
11
- } from "./chunk-N7MHVCML.js";
11
+ } from "./chunk-PAXP5KZC.js";
12
12
  import {
13
13
  loadConfig
14
14
  } from "./chunk-YVY23HNW.js";
@@ -24,7 +24,7 @@ import {
24
24
  createRunCompetitorResolver,
25
25
  readMarketCompetitorNames,
26
26
  refreshSnapshotMentionIdentity
27
- } from "./chunk-WEDOXGGI.js";
27
+ } from "./chunk-42OW42AR.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-XDMZTN3T.js");
432
+ const { IntelligenceService } = await import("./intelligence-service-RRKHXZ2N.js");
433
433
  const config = loadConfig();
434
434
  const db = createClient(config.database);
435
435
  migrate(db);
@@ -75056,6 +75056,7 @@ async function technicalAeoRoutes(app, opts) {
75056
75056
  const resolveCrawl = (projectId, runId, requestedDate, scope = {}) => {
75057
75057
  const filters = visibleCrawlFilters(projectId);
75058
75058
  if (scope.recordedBefore) filters.push(lt17(siteCrawlSnapshots.createdAt, scope.recordedBefore));
75059
+ const newestIfComplete = sql43`case when ${siteCrawlSnapshots.complete} then ${siteCrawlSnapshots.createdAt} end`;
75059
75060
  if (requestedDate) {
75060
75061
  const nextDate2 = /* @__PURE__ */ new Date(`${requestedDate}T00:00:00.000Z`);
75061
75062
  nextDate2.setUTCDate(nextDate2.getUTCDate() + 1);
@@ -75065,6 +75066,7 @@ async function technicalAeoRoutes(app, opts) {
75065
75066
  const selected = app.db.select({ snapshot: siteCrawlSnapshots, runStatus: runs.status }).from(siteCrawlSnapshots).innerJoin(runs, eq109(siteCrawlSnapshots.runId, runs.id)).where(and92(...selectionFilters, runId ? eq109(siteCrawlSnapshots.runId, runId) : void 0)).orderBy(
75066
75067
  desc50(sql43`substr(${siteCrawlSnapshots.createdAt}, 1, 10)`),
75067
75068
  desc50(siteCrawlSnapshots.complete),
75069
+ desc50(newestIfComplete),
75068
75070
  desc50(siteCrawlSnapshots.pagesFetched),
75069
75071
  desc50(siteCrawlSnapshots.createdAt),
75070
75072
  desc50(siteCrawlSnapshots.runId)
@@ -75086,6 +75088,7 @@ async function technicalAeoRoutes(app, opts) {
75086
75088
  pages: siteCrawlSnapshots.pagesFetched
75087
75089
  }).from(siteCrawlSnapshots).innerJoin(runs, eq109(siteCrawlSnapshots.runId, runs.id)).where(sameDate).orderBy(
75088
75090
  desc50(siteCrawlSnapshots.complete),
75091
+ desc50(newestIfComplete),
75089
75092
  desc50(siteCrawlSnapshots.pagesFetched),
75090
75093
  desc50(siteCrawlSnapshots.createdAt),
75091
75094
  desc50(siteCrawlSnapshots.runId)
@@ -75106,9 +75109,11 @@ async function technicalAeoRoutes(app, opts) {
75106
75109
  ...recordedBefore ? [lt17(siteAuditSnapshots.createdAt, recordedBefore)] : []
75107
75110
  ];
75108
75111
  const complete = sql43`case when ${runs.status} = ${RunStatuses.completed} then 1 else 0 end`;
75112
+ const newestIfComplete = sql43`case when ${runs.status} = ${RunStatuses.completed} then ${siteAuditSnapshots.createdAt} end`;
75109
75113
  const selectAudit = (pinnedRunId) => app.db.select({ snap: siteAuditSnapshots, runStatus: runs.status }).from(siteAuditSnapshots).innerJoin(runs, eq109(siteAuditSnapshots.runId, runs.id)).where(and92(...filters, pinnedRunId ? eq109(siteAuditSnapshots.runId, pinnedRunId) : void 0)).orderBy(
75110
75114
  desc50(sql43`substr(${siteAuditSnapshots.createdAt}, 1, 10)`),
75111
75115
  desc50(complete),
75116
+ desc50(newestIfComplete),
75112
75117
  desc50(siteAuditSnapshots.pagesAudited),
75113
75118
  desc50(siteAuditSnapshots.createdAt),
75114
75119
  desc50(siteAuditSnapshots.runId)
@@ -75140,6 +75145,7 @@ async function technicalAeoRoutes(app, opts) {
75140
75145
  pages: siteAuditSnapshots.pagesAudited
75141
75146
  }).from(siteAuditSnapshots).innerJoin(runs, eq109(siteAuditSnapshots.runId, runs.id)).where(sameDate).orderBy(
75142
75147
  desc50(complete),
75148
+ desc50(newestIfComplete),
75143
75149
  desc50(siteAuditSnapshots.pagesAudited),
75144
75150
  desc50(siteAuditSnapshots.createdAt),
75145
75151
  desc50(siteAuditSnapshots.runId)
@@ -5,7 +5,7 @@ import {
5
5
  isStoredPageReadTool,
6
6
  isStoredReadTool,
7
7
  truncateToolResult
8
- } from "./chunk-4F6X52HV.js";
8
+ } from "./chunk-FAXYDTV5.js";
9
9
  import {
10
10
  CANONRY_MCP_TOOLKITS,
11
11
  resolveAeroSkillDir
@@ -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-IMMMFC4N.js");
731
+ const { demoCommand } = await import("./demo-KMVR3ZWW.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-5L4DWEWP.js");
752
+ const { backfillAnswerVisibilityCommand } = await import("./backfill-KDTC6JEP.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-5L4DWEWP.js");
769
+ const { backfillAnswerMentionsCommand } = await import("./backfill-KDTC6JEP.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-5L4DWEWP.js");
787
+ const { backfillInsightsCommand } = await import("./backfill-KDTC6JEP.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-5L4DWEWP.js");
807
+ const { backfillNormalizedPathsCommand } = await import("./backfill-KDTC6JEP.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-5L4DWEWP.js");
822
+ const { backfillAiReferralPathsCommand } = await import("./backfill-KDTC6JEP.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-5L4DWEWP.js");
834
+ const { backfillSnapshotAttributionCommand } = await import("./backfill-KDTC6JEP.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-5L4DWEWP.js");
853
+ const { backfillTrafficClassificationCommand } = await import("./backfill-KDTC6JEP.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-K32TQKTC.js");
1497
+ const { resetDashboardPassword } = await import("./dashboard-JLCJDU2V.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-RVBNEPWA.js"), import("./cli-commands-2Q6ETPXR.js")]);
7164
+ const [{ printCliCatalog }, { REGISTERED_CLI_COMMANDS: REGISTERED_CLI_COMMANDS2 }] = await Promise.all([import("./cli-catalog-RVBNEPWA.js"), import("./cli-commands-6ZOUHE3V.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-ILS6UQCH.js");
7213
+ const { initCommand } = await import("./init-TAIUP5GV.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-AEICU77K.js");
7268
+ const { serveCommand } = await import("./serve-PGPQOVGC.js");
7269
7269
  await serveCommand(input.format);
7270
7270
  }
7271
7271
  },
@@ -8656,8 +8656,8 @@ var AGENT_CLI_COMMANDS = [
8656
8656
  "timeout-ms": stringOption()
8657
8657
  },
8658
8658
  run: async (input) => {
8659
- const { coerceAgentProvider } = await import("./session-TERRMJL7.js");
8660
- const { AERO_TOOL_PROFILES, isAeroToolProfile } = await import("./tools-3A3I2TX2.js");
8659
+ const { coerceAgentProvider } = await import("./session-MNEWM2CT.js");
8660
+ const { AERO_TOOL_PROFILES, isAeroToolProfile } = await import("./tools-4STRCC7Q.js");
8661
8661
  const { agentAsk } = await import("./agent-ask-EBYJSSGR.js");
8662
8662
  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]`;
8663
8663
  const project3 = requireProject(input, "agent.ask", usage);
@@ -10,7 +10,7 @@ import {
10
10
  } from "./chunk-HGMYEDAQ.js";
11
11
  import {
12
12
  buildOpenApiDocument
13
- } from "./chunk-WEDOXGGI.js";
13
+ } from "./chunk-42OW42AR.js";
14
14
  import {
15
15
  DEFAULT_COMPETITOR_AUTO_ALIAS_MODE,
16
16
  MeasurementPortfolioLists,
@@ -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-AEICU77K.js");
50
+ const { serveCommand } = await import("./serve-PGPQOVGC.js");
51
51
  await serveCommand(format);
52
52
  }
53
53
 
@@ -17,7 +17,7 @@ import {
17
17
  mergeGscQueryTotalsWithFallback,
18
18
  readGscQueryDailyRows,
19
19
  readLatestGscDataDate
20
- } from "./chunk-WEDOXGGI.js";
20
+ } from "./chunk-42OW42AR.js";
21
21
  import {
22
22
  competitors,
23
23
  gbpDailyMetrics,
@@ -6,7 +6,7 @@ import {
6
6
  correctBackgroundCallJourneys,
7
7
  mergeSplitJourneyVisitors,
8
8
  writeUnrecognizedAgentBuckets
9
- } from "./chunk-WEDOXGGI.js";
9
+ } from "./chunk-42OW42AR.js";
10
10
  import {
11
11
  AGENT_TRUST_RULES_VERSION,
12
12
  BROWSER_SHAPED_AGENT_MARKERS,
@@ -27,14 +27,14 @@ import {
27
27
  resolveConfiguredAgentProvider,
28
28
  resolveSessionProviderAndModel,
29
29
  setAeroSystemPrompt
30
- } from "./chunk-GDFU7FOR.js";
30
+ } from "./chunk-6PNFPMLD.js";
31
31
  import {
32
32
  AeroToolProfiles,
33
33
  AeroToolScopes,
34
34
  buildAeroStateTools,
35
35
  isAeroToolProfile,
36
36
  truncateToolResult
37
- } from "./chunk-4F6X52HV.js";
37
+ } from "./chunk-FAXYDTV5.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-N7MHVCML.js";
68
+ } from "./chunk-PAXP5KZC.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-YPHRRCS3.js";
165
+ } from "./chunk-NL2WM6OB.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-WEDOXGGI.js";
319
+ } from "./chunk-42OW42AR.js";
320
320
  import {
321
321
  OperationalLogStore,
322
322
  SentimentIdempotencyConflict,
@@ -5975,7 +5975,7 @@ function nonBlank(value) {
5975
5975
  return trimmed ? trimmed : void 0;
5976
5976
  }
5977
5977
  function resolveBuildCommit(env = process.env) {
5978
- const embedded = true ? "f6c4ce076983d374b95618d1a3a2dc65fc602f37" : void 0;
5978
+ const embedded = true ? "027e1a48f82091e0f55aad90ad05bd5c09e70592" : void 0;
5979
5979
  return nonBlank(embedded) ?? nonBlank(env.CANONRY_COMMIT);
5980
5980
  }
5981
5981
  function resolveInstanceIdentity(env = process.env) {
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  REGISTERED_CLI_COMMANDS
3
- } from "./chunk-UJL5K3LB.js";
3
+ } from "./chunk-DXXHZHPE.js";
4
4
  import "./chunk-6GO5VVAC.js";
5
5
  import "./chunk-VJWDBFSL.js";
6
6
  import "./chunk-W6H7WDHW.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-UJL5K3LB.js";
4
+ } from "./chunk-DXXHZHPE.js";
5
5
  import "./chunk-6GO5VVAC.js";
6
6
  import {
7
7
  buildSetupState,
8
8
  runPendingServeHandoff
9
- } from "./chunk-PC27ODE3.js";
9
+ } from "./chunk-M322ZEOQ.js";
10
10
  import "./chunk-VJWDBFSL.js";
11
11
  import "./chunk-W6H7WDHW.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-WEDOXGGI.js";
10
+ } from "./chunk-42OW42AR.js";
11
11
  import "./chunk-NAPFULBT.js";
12
12
  import "./chunk-3HNHOS6O.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-TFEWWKQ3.js");
43
+ const { createDemoServer } = await import("./demo-server-QXI7BGMM.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-YPHRRCS3.js";
21
+ } from "./chunk-NL2WM6OB.js";
22
22
  import {
23
23
  determineCitationState
24
24
  } from "./chunk-P4MNYMJJ.js";
@@ -26,7 +26,7 @@ import "./chunk-SYOQULRL.js";
26
26
  import {
27
27
  apiRoutes,
28
28
  assessConversionTrackingIntegrity
29
- } from "./chunk-WEDOXGGI.js";
29
+ } from "./chunk-42OW42AR.js";
30
30
  import "./chunk-NAPFULBT.js";
31
31
  import "./chunk-3HNHOS6O.js";
32
32
  import {
package/dist/index.d.ts CHANGED
@@ -1831,7 +1831,7 @@ declare const seoProfiles: drizzle_orm_sqlite_core.SQLiteTableWithColumns<{
1831
1831
  languageCode: string;
1832
1832
  limit: number;
1833
1833
  scope: {
1834
- kind: "project" | "property" | "market" | "group";
1834
+ kind: "property" | "project" | "market" | "group";
1835
1835
  key?: string | undefined;
1836
1836
  expectedPlanRevision?: number | undefined;
1837
1837
  };
@@ -1876,7 +1876,7 @@ declare const seoProfiles: drizzle_orm_sqlite_core.SQLiteTableWithColumns<{
1876
1876
  languageCode: string;
1877
1877
  limit: number;
1878
1878
  scope: {
1879
- kind: "project" | "property" | "market" | "group";
1879
+ kind: "property" | "project" | "market" | "group";
1880
1880
  key?: string | undefined;
1881
1881
  expectedPlanRevision?: number | undefined;
1882
1882
  };
@@ -2073,7 +2073,7 @@ declare const seoJobs: drizzle_orm_sqlite_core.SQLiteTableWithColumns<{
2073
2073
  languageCode: string;
2074
2074
  limit: number;
2075
2075
  scope: {
2076
- kind: "project" | "property" | "market" | "group";
2076
+ kind: "property" | "project" | "market" | "group";
2077
2077
  key?: string | undefined;
2078
2078
  expectedPlanRevision?: number | undefined;
2079
2079
  };
@@ -2118,7 +2118,7 @@ declare const seoJobs: drizzle_orm_sqlite_core.SQLiteTableWithColumns<{
2118
2118
  languageCode: string;
2119
2119
  limit: number;
2120
2120
  scope: {
2121
- kind: "project" | "property" | "market" | "group";
2121
+ kind: "property" | "project" | "market" | "group";
2122
2122
  key?: string | undefined;
2123
2123
  expectedPlanRevision?: number | undefined;
2124
2124
  };
@@ -6256,7 +6256,7 @@ declare const querySnapshots: drizzle_orm_sqlite_core.SQLiteTableWithColumns<{
6256
6256
  tableName: "query_snapshots";
6257
6257
  dataType: "string";
6258
6258
  columnType: "SQLiteText";
6259
- data: "unknown" | "used" | "not-used" | "not-applicable";
6259
+ data: "unknown" | "not-applicable" | "used" | "not-used";
6260
6260
  driverParam: string;
6261
6261
  notNull: false;
6262
6262
  hasDefault: false;
@@ -6269,7 +6269,7 @@ declare const querySnapshots: drizzle_orm_sqlite_core.SQLiteTableWithColumns<{
6269
6269
  generated: undefined;
6270
6270
  }, {}, {
6271
6271
  length: number | undefined;
6272
- $type: "unknown" | "used" | "not-used" | "not-applicable";
6272
+ $type: "unknown" | "not-applicable" | "used" | "not-used";
6273
6273
  }>;
6274
6274
  retrievalContract: drizzle_orm_sqlite_core.SQLiteColumn<{
6275
6275
  name: "retrieval_contract";
@@ -6617,7 +6617,7 @@ declare const querySnapshots: drizzle_orm_sqlite_core.SQLiteTableWithColumns<{
6617
6617
  status?: string | null | undefined;
6618
6618
  }[];
6619
6619
  searchQueries: string[];
6620
- retrievalStatus: "unknown" | "used" | "not-used" | "not-applicable";
6620
+ retrievalStatus: "unknown" | "not-applicable" | "used" | "not-used";
6621
6621
  citationBasis: "none" | "mixed" | "answer-support" | "explicit-citation";
6622
6622
  citationMeasurable: boolean;
6623
6623
  directSourceUrls: boolean;
@@ -6722,7 +6722,7 @@ declare const querySnapshots: drizzle_orm_sqlite_core.SQLiteTableWithColumns<{
6722
6722
  status?: string | null | undefined;
6723
6723
  }[];
6724
6724
  searchQueries: string[];
6725
- retrievalStatus: "unknown" | "used" | "not-used" | "not-applicable";
6725
+ retrievalStatus: "unknown" | "not-applicable" | "used" | "not-used";
6726
6726
  citationBasis: "none" | "mixed" | "answer-support" | "explicit-citation";
6727
6727
  citationMeasurable: boolean;
6728
6728
  directSourceUrls: boolean;
@@ -12454,7 +12454,7 @@ declare const siteAuditSnapshots: drizzle_orm_sqlite_core.SQLiteTableWithColumns
12454
12454
  weight: number;
12455
12455
  sharePct: number | null;
12456
12456
  avgScore: number;
12457
- status: "partial" | "fail" | "pass";
12457
+ status: "fail" | "partial" | "pass";
12458
12458
  pagesPassing: number;
12459
12459
  pagesPartial: number;
12460
12460
  pagesFailing: number;
@@ -12476,7 +12476,7 @@ declare const siteAuditSnapshots: drizzle_orm_sqlite_core.SQLiteTableWithColumns
12476
12476
  weight: number;
12477
12477
  sharePct: number | null;
12478
12478
  avgScore: number;
12479
- status: "partial" | "fail" | "pass";
12479
+ status: "fail" | "partial" | "pass";
12480
12480
  pagesPassing: number;
12481
12481
  pagesPartial: number;
12482
12482
  pagesFailing: number;
@@ -29926,7 +29926,7 @@ declare const researchRunQueries: drizzle_orm_sqlite_core.SQLiteTableWithColumns
29926
29926
  status?: string | null | undefined;
29927
29927
  }[];
29928
29928
  searchQueries: string[];
29929
- retrievalStatus: "unknown" | "used" | "not-used" | "not-applicable";
29929
+ retrievalStatus: "unknown" | "not-applicable" | "used" | "not-used";
29930
29930
  citationBasis: "none" | "mixed" | "answer-support" | "explicit-citation";
29931
29931
  citationMeasurable: boolean;
29932
29932
  directSourceUrls: boolean;
@@ -30031,7 +30031,7 @@ declare const researchRunQueries: drizzle_orm_sqlite_core.SQLiteTableWithColumns
30031
30031
  status?: string | null | undefined;
30032
30032
  }[];
30033
30033
  searchQueries: string[];
30034
- retrievalStatus: "unknown" | "used" | "not-used" | "not-applicable";
30034
+ retrievalStatus: "unknown" | "not-applicable" | "used" | "not-used";
30035
30035
  citationBasis: "none" | "mixed" | "answer-support" | "explicit-citation";
30036
30036
  citationMeasurable: boolean;
30037
30037
  directSourceUrls: boolean;
@@ -33015,7 +33015,7 @@ declare const gbpReviews: drizzle_orm_sqlite_core.SQLiteTableWithColumns<{
33015
33015
  tableName: "gbp_reviews";
33016
33016
  dataType: "string";
33017
33017
  columnType: "SQLiteText";
33018
- data: "none" | "baseline" | "stale" | "pending" | "sent" | "skipped" | "suppressed";
33018
+ data: "none" | "baseline" | "stale" | "skipped" | "pending" | "sent" | "suppressed";
33019
33019
  driverParam: string;
33020
33020
  notNull: true;
33021
33021
  hasDefault: true;
@@ -33028,7 +33028,7 @@ declare const gbpReviews: drizzle_orm_sqlite_core.SQLiteTableWithColumns<{
33028
33028
  generated: undefined;
33029
33029
  }, {}, {
33030
33030
  length: number | undefined;
33031
- $type: "none" | "baseline" | "stale" | "pending" | "sent" | "skipped" | "suppressed";
33031
+ $type: "none" | "baseline" | "stale" | "skipped" | "pending" | "sent" | "suppressed";
33032
33032
  }>;
33033
33033
  alertStateAt: drizzle_orm_sqlite_core.SQLiteColumn<{
33034
33034
  name: "alert_state_at";
@@ -33325,7 +33325,7 @@ declare const gbpReviewRatings: drizzle_orm_sqlite_core.SQLiteTableWithColumns<{
33325
33325
  tableName: "gbp_review_ratings";
33326
33326
  dataType: "string";
33327
33327
  columnType: "SQLiteText";
33328
- data: "none" | "baseline" | "stale" | "pending" | "sent" | "skipped" | "suppressed";
33328
+ data: "none" | "baseline" | "stale" | "skipped" | "pending" | "sent" | "suppressed";
33329
33329
  driverParam: string;
33330
33330
  notNull: true;
33331
33331
  hasDefault: true;
@@ -33338,7 +33338,7 @@ declare const gbpReviewRatings: drizzle_orm_sqlite_core.SQLiteTableWithColumns<{
33338
33338
  generated: undefined;
33339
33339
  }, {}, {
33340
33340
  length: number | undefined;
33341
- $type: "none" | "baseline" | "stale" | "pending" | "sent" | "skipped" | "suppressed";
33341
+ $type: "none" | "baseline" | "stale" | "skipped" | "pending" | "sent" | "suppressed";
33342
33342
  }>;
33343
33343
  alertStateAt: drizzle_orm_sqlite_core.SQLiteColumn<{
33344
33344
  name: "alert_state_at";
@@ -34584,7 +34584,7 @@ declare const adsOperationSteps: drizzle_orm_sqlite_core.SQLiteTableWithColumns<
34584
34584
  tableName: "ads_operation_steps";
34585
34585
  dataType: "string";
34586
34586
  columnType: "SQLiteText";
34587
- data: "unknown" | "failed" | "active" | "pending" | "executing" | "rollback_executing" | "rolled_back" | "rollback_failed";
34587
+ data: "unknown" | "active" | "failed" | "pending" | "executing" | "rollback_executing" | "rolled_back" | "rollback_failed";
34588
34588
  driverParam: string;
34589
34589
  notNull: true;
34590
34590
  hasDefault: false;
@@ -34597,7 +34597,7 @@ declare const adsOperationSteps: drizzle_orm_sqlite_core.SQLiteTableWithColumns<
34597
34597
  generated: undefined;
34598
34598
  }, {}, {
34599
34599
  length: number | undefined;
34600
- $type: "unknown" | "failed" | "active" | "pending" | "executing" | "rollback_executing" | "rolled_back" | "rollback_failed";
34600
+ $type: "unknown" | "active" | "failed" | "pending" | "executing" | "rollback_executing" | "rolled_back" | "rollback_failed";
34601
34601
  }>;
34602
34602
  providerUpdatedAt: drizzle_orm_sqlite_core.SQLiteColumn<{
34603
34603
  name: "provider_updated_at";
package/dist/index.js CHANGED
@@ -3,14 +3,14 @@ import {
3
3
  createGoogleMarketingCredentialStore,
4
4
  createGoogleMarketingRuntime,
5
5
  createServer
6
- } from "./chunk-HT7FQ45E.js";
6
+ } from "./chunk-VFQMRUGN.js";
7
7
  import "./chunk-AXWUCOYT.js";
8
- import "./chunk-GDFU7FOR.js";
9
- import "./chunk-4F6X52HV.js";
8
+ import "./chunk-6PNFPMLD.js";
9
+ import "./chunk-FAXYDTV5.js";
10
10
  import "./chunk-ELCLGWUT.js";
11
11
  import "./chunk-XEBKF4N5.js";
12
12
  import "./chunk-LSIE5MHG.js";
13
- import "./chunk-N7MHVCML.js";
13
+ import "./chunk-PAXP5KZC.js";
14
14
  import "./chunk-6DP2YPZY.js";
15
15
  import "./chunk-TSENU4GG.js";
16
16
  import "./chunk-WOEGZKXQ.js";
@@ -28,10 +28,10 @@ import "./chunk-IQ5RKJKQ.js";
28
28
  import "./chunk-L5U7VT4A.js";
29
29
  import "./chunk-AOJU5LKX.js";
30
30
  import "./chunk-HGMYEDAQ.js";
31
- import "./chunk-YPHRRCS3.js";
31
+ import "./chunk-NL2WM6OB.js";
32
32
  import "./chunk-P4MNYMJJ.js";
33
33
  import "./chunk-SYOQULRL.js";
34
- import "./chunk-WEDOXGGI.js";
34
+ import "./chunk-42OW42AR.js";
35
35
  import "./chunk-NAPFULBT.js";
36
36
  import "./chunk-3HNHOS6O.js";
37
37
  import "./chunk-C3BSCGUH.js";
@@ -7,7 +7,7 @@ import {
7
7
  import {
8
8
  buildSetupState,
9
9
  queueServeHandoff
10
- } from "./chunk-PC27ODE3.js";
10
+ } from "./chunk-M322ZEOQ.js";
11
11
  import "./chunk-VJWDBFSL.js";
12
12
  import "./chunk-6DP2YPZY.js";
13
13
  import "./chunk-WOEGZKXQ.js";
@@ -1,10 +1,10 @@
1
1
  import {
2
2
  HISTORY_WINDOW_RUNS,
3
3
  IntelligenceService
4
- } from "./chunk-YPHRRCS3.js";
4
+ } from "./chunk-NL2WM6OB.js";
5
5
  import "./chunk-P4MNYMJJ.js";
6
6
  import "./chunk-SYOQULRL.js";
7
- import "./chunk-WEDOXGGI.js";
7
+ import "./chunk-42OW42AR.js";
8
8
  import "./chunk-NAPFULBT.js";
9
9
  import "./chunk-3HNHOS6O.js";
10
10
  import "./chunk-C3BSCGUH.js";
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  backfillAiReferralPaths,
3
3
  backfillNormalizedPaths
4
- } from "./chunk-6Y4EVLV2.js";
4
+ } from "./chunk-3MIZP4IB.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-HT7FQ45E.js";
12
+ } from "./chunk-VFQMRUGN.js";
13
13
  import "./chunk-AXWUCOYT.js";
14
- import "./chunk-GDFU7FOR.js";
15
- import "./chunk-4F6X52HV.js";
14
+ import "./chunk-6PNFPMLD.js";
15
+ import "./chunk-FAXYDTV5.js";
16
16
  import "./chunk-ELCLGWUT.js";
17
17
  import "./chunk-XEBKF4N5.js";
18
18
  import "./chunk-LSIE5MHG.js";
19
- import "./chunk-N7MHVCML.js";
19
+ import "./chunk-PAXP5KZC.js";
20
20
  import {
21
21
  trackFeatureCompleted
22
22
  } from "./chunk-6DP2YPZY.js";
@@ -57,13 +57,13 @@ import {
57
57
  CliError,
58
58
  isMachineFormat
59
59
  } from "./chunk-HGMYEDAQ.js";
60
- import "./chunk-YPHRRCS3.js";
60
+ import "./chunk-NL2WM6OB.js";
61
61
  import "./chunk-P4MNYMJJ.js";
62
62
  import "./chunk-SYOQULRL.js";
63
63
  import {
64
64
  refreshSnapshotMentionIdentity,
65
65
  snapshotsWithSentimentResults
66
- } from "./chunk-WEDOXGGI.js";
66
+ } from "./chunk-42OW42AR.js";
67
67
  import "./chunk-NAPFULBT.js";
68
68
  import "./chunk-3HNHOS6O.js";
69
69
  import {
@@ -9,8 +9,8 @@ import {
9
9
  resolveAeroModel,
10
10
  resolveConfiguredAgentProvider,
11
11
  resolveSessionProviderAndModel
12
- } from "./chunk-GDFU7FOR.js";
13
- import "./chunk-4F6X52HV.js";
12
+ } from "./chunk-6PNFPMLD.js";
13
+ import "./chunk-FAXYDTV5.js";
14
14
  import {
15
15
  resolveAeroSkillDir
16
16
  } from "./chunk-MTW37GXF.js";
@@ -26,7 +26,7 @@ import "./chunk-L5U7VT4A.js";
26
26
  import "./chunk-AOJU5LKX.js";
27
27
  import "./chunk-HGMYEDAQ.js";
28
28
  import "./chunk-SYOQULRL.js";
29
- import "./chunk-WEDOXGGI.js";
29
+ import "./chunk-42OW42AR.js";
30
30
  import "./chunk-NAPFULBT.js";
31
31
  import "./chunk-3HNHOS6O.js";
32
32
  import "./chunk-C3BSCGUH.js";
@@ -11,7 +11,7 @@ import {
11
11
  buildAllTools,
12
12
  buildReadTools,
13
13
  isAeroToolProfile
14
- } from "./chunk-4F6X52HV.js";
14
+ } from "./chunk-FAXYDTV5.js";
15
15
  import "./chunk-WTKGSKCS.js";
16
16
  import "./chunk-YVY23HNW.js";
17
17
  import "./chunk-IHMODTQ7.js";
@@ -19,7 +19,7 @@ import "./chunk-IQ5RKJKQ.js";
19
19
  import "./chunk-L5U7VT4A.js";
20
20
  import "./chunk-AOJU5LKX.js";
21
21
  import "./chunk-HGMYEDAQ.js";
22
- import "./chunk-WEDOXGGI.js";
22
+ import "./chunk-42OW42AR.js";
23
23
  import "./chunk-NAPFULBT.js";
24
24
  import "./chunk-3HNHOS6O.js";
25
25
  import "./chunk-C3BSCGUH.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@canonry/canonry",
3
- "version": "7.91.0",
3
+ "version": "7.91.1",
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": [