@ainyc/canonry 1.46.0 → 1.46.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.
@@ -0,0 +1,339 @@
1
+ # Canonry CLI Reference
2
+
3
+ ## Server Management
4
+
5
+ ```bash
6
+ canonry init # interactive setup
7
+ canonry bootstrap # non-interactive setup from env vars
8
+ canonry start # start daemon
9
+ canonry stop # stop daemon
10
+ canonry serve # foreground mode
11
+ canonry serve --host 0.0.0.0 --port 4100
12
+ canonry --version
13
+ ```
14
+
15
+ Production managed by PM2:
16
+ ```bash
17
+ pm2 status
18
+ pm2 logs canonry
19
+ pm2 restart canonry
20
+ ```
21
+
22
+ ## Project Management
23
+
24
+ ```bash
25
+ canonry project list # list all projects
26
+ canonry project create <name> --domain <url> --country US --language en
27
+ canonry project show <name> # project detail
28
+ canonry project update <name> # update project settings
29
+ canonry project delete <name> # delete a project
30
+ canonry status <project> # citation summary + domain info
31
+ ```
32
+
33
+ ### Locations
34
+
35
+ Projects support multi-region location context for geographically-aware sweeps:
36
+
37
+ ```bash
38
+ canonry project add-location <name> --label "NYC" --city "New York" --region NY --country US
39
+ canonry project locations <name> # list configured locations
40
+ canonry project set-default-location <name> <label>
41
+ canonry project remove-location <name> <label>
42
+ ```
43
+
44
+ ## Sweeps
45
+
46
+ ```bash
47
+ canonry snapshot "Acme Corp" --domain acme.example.com # one-shot sales snapshot
48
+ canonry snapshot "Acme Corp" --domain acme.example.com --md # save markdown report
49
+ canonry snapshot "Acme Corp" --domain acme.example.com --output report.md # custom path
50
+ canonry snapshot "Acme Corp" --domain acme.example.com --pdf # save PDF report
51
+ canonry snapshot "Acme Corp" --domain acme.example.com --format json
52
+
53
+ canonry run <project> # sweep all configured providers
54
+ canonry run <project> --provider gemini # single provider only
55
+ canonry run <project> --wait # block until complete
56
+ canonry run <project> --location <label> # run with specific location context
57
+ canonry run <project> --all-locations # run for every configured location
58
+ canonry run <project> --no-location # explicitly skip location context
59
+ canonry run --all --wait # all projects
60
+ canonry run cancel <project> [run-id] # force-cancel stuck runs
61
+ canonry runs <project> --limit 10 # list recent runs
62
+ canonry run show <id> # show run details
63
+ ```
64
+
65
+ Run statuses: `queued` → `running` → `completed` / `failed` / `partial`
66
+
67
+ `partial` = some providers failed (usually rate limits) — successful snapshots are still saved.
68
+
69
+ `snapshot` does not create a project or write to the DB. It generates category queries, runs providers, and produces a report for prospecting.
70
+
71
+ ## Citation Data
72
+
73
+ ```bash
74
+ canonry evidence <project> # per-keyword cited/not-cited
75
+ canonry evidence <project> --format json # JSON output
76
+ canonry history <project> # audit trail
77
+ canonry export <project> --include-results # export as YAML
78
+ canonry backfill answer-visibility # recompute answer visibility from stored answers
79
+ canonry backfill answer-visibility --project <name> --format json
80
+ ```
81
+
82
+ Output shows:
83
+ - `✓ cited` — domain appeared in AI response for that keyword
84
+ - `✗ not-cited` — domain did not appear
85
+ - Summary: `Cited: X / Y`
86
+
87
+ ## Analytics
88
+
89
+ ```bash
90
+ canonry analytics <project> # default analytics view
91
+ canonry analytics <project> --feature metrics # citation rate trends
92
+ canonry analytics <project> --feature gaps # brand gap analysis (cited/gap/uncited)
93
+ canonry analytics <project> --feature sources # source breakdown by category
94
+ canonry analytics <project> --window 7d # time window: 7d, 30d, 90d, all
95
+ ```
96
+
97
+ ## Intelligence
98
+
99
+ ```bash
100
+ canonry insights <project> # list active insights (regressions, gains, opportunities)
101
+ canonry insights <project> --dismissed # include dismissed insights
102
+ canonry insights <project> --format json # JSON output
103
+ canonry insights dismiss <project> <id> # dismiss an insight
104
+ canonry health <project> # latest citation health snapshot
105
+ canonry health <project> --history # health trend over time
106
+ canonry health <project> --history --limit 10 # limit history entries
107
+ canonry health <project> --format json # JSON output
108
+ canonry backfill insights <project> # backfill insights for all completed runs
109
+ canonry backfill insights <project> --from-run <id> --to-run <id> # backfill a range
110
+ ```
111
+
112
+ ## Keywords & Competitors
113
+
114
+ ```bash
115
+ canonry keyword add <project> "phrase one" "phrase two"
116
+ canonry keyword remove <project> "phrase"
117
+ canonry keyword list <project>
118
+ canonry keyword import <project> keywords.txt
119
+ canonry keyword generate <project> --provider gemini --count 10 --save
120
+
121
+ canonry competitor add <project> competitor1.com competitor2.com
122
+ canonry competitor list <project>
123
+ ```
124
+
125
+ ## Scheduling & Notifications
126
+
127
+ ```bash
128
+ canonry schedule set <project> --preset daily # or: weekly, twice-daily, daily@09
129
+ canonry schedule set <project> --cron "0 9 * * *" --timezone America/New_York
130
+ canonry schedule show <project>
131
+ canonry schedule enable <project>
132
+ canonry schedule disable <project>
133
+ canonry schedule remove <project>
134
+
135
+ canonry notify add <project> --webhook <url> --events citation.lost,citation.gained
136
+ canonry notify events # list all available event types
137
+ canonry notify list <project>
138
+ canonry notify remove <project> <id>
139
+ canonry notify test <project> <id>
140
+ ```
141
+
142
+ Available events: `citation.lost`, `citation.gained`, `run.completed`, `run.failed`
143
+
144
+ ## Provider Settings & Quotas
145
+
146
+ ```bash
147
+ canonry settings # show config: providers, apiUrl, db path
148
+ canonry settings --format json
149
+ canonry settings provider gemini --api-key <KEY> --model gemini-2.5-flash
150
+ canonry settings provider openai --max-per-day 1000 --max-per-minute 20
151
+ canonry settings provider perplexity --api-key <KEY>
152
+ ```
153
+
154
+ Quota flags: `--max-concurrent`, `--max-per-minute`, `--max-per-day`
155
+
156
+ Available providers: `gemini`, `openai`, `claude`, `perplexity`, `local`, `cdp`
157
+
158
+ If a provider hits rate limits (429 errors), the run completes as `partial`. Reduce concurrency or increase time between sweeps.
159
+
160
+ ### Gemini Vertex AI
161
+
162
+ Gemini supports Vertex AI as an alternative to API key authentication. Use GCP Application Default Credentials (ADC) or a service account JSON key file:
163
+
164
+ ```bash
165
+ # Via env vars (recommended for servers)
166
+ export GEMINI_VERTEX_PROJECT=my-gcp-project
167
+ export GEMINI_VERTEX_REGION=us-central1 # optional, defaults to us-central1
168
+ export GEMINI_VERTEX_CREDENTIALS=/path/to/sa.json # optional, falls back to ADC
169
+
170
+ # Or in canonry.yaml config
171
+ # vertexProject, vertexRegion, vertexCredentials fields under provider config
172
+ ```
173
+
174
+ When Vertex AI is configured, no `GEMINI_API_KEY` is required. The provider uses the `@google-cloud/vertexai` SDK with `googleAuthOptions` for credential handling.
175
+
176
+ ## Google Search Console
177
+
178
+ ```bash
179
+ canonry google connect <project> # initiate OAuth flow
180
+ canonry google disconnect <project> # disconnect GSC
181
+ canonry google status <project> # connection status
182
+ canonry google properties <project> # list available properties
183
+ canonry google set-property <project> <url> # set GSC property URL
184
+ canonry google set-sitemap <project> <url> # set sitemap URL
185
+ canonry google list-sitemaps <project> # list submitted sitemaps
186
+ canonry google discover-sitemaps <project> --wait # auto-discover and inspect
187
+
188
+ canonry google sync <project> # sync GSC data
189
+ canonry google sync <project> --days 30 --full --wait # full sync with wait
190
+
191
+ canonry google coverage <project> # index coverage summary
192
+ canonry google refresh <project> # force-fetch fresh GSC coverage data
193
+ canonry google performance <project> # search performance data
194
+ canonry google performance <project> --days 30 --keyword "term" --page "/url"
195
+
196
+ canonry google inspect <project> <url> # inspect specific URL
197
+ canonry google inspect-sitemap <project> --wait # bulk inspect all sitemap URLs
198
+ canonry google inspections <project> # inspection history
199
+ canonry google inspections <project> --url <url> # filter by URL
200
+ canonry google deindexed <project> # pages that lost indexing
201
+
202
+ canonry google request-indexing <project> <url> # push URL to Google
203
+ canonry google request-indexing <project> --all-unindexed # push all unknown pages
204
+ ```
205
+
206
+ ## Bing Webmaster Tools
207
+
208
+ ```bash
209
+ canonry bing connect <project> --api-key <key> # connect Bing WMT
210
+ canonry bing disconnect <project> # disconnect
211
+ canonry bing status <project> # connection status
212
+ canonry bing sites <project> # list verified sites
213
+ canonry bing set-site <project> <url> # set active site URL
214
+ canonry bing coverage <project> # URL coverage data
215
+ canonry bing refresh <project> # force-fetch fresh Bing coverage data
216
+ canonry bing inspect <project> <url> # inspect specific URL
217
+ canonry bing inspections <project> # inspection history
218
+ canonry bing request-indexing <project> <url> # submit URL for indexing
219
+ canonry bing request-indexing <project> --all-unindexed # submit all unindexed
220
+ canonry bing performance <project> # search performance data
221
+ ```
222
+
223
+ ## WordPress Integration
224
+
225
+ ```bash
226
+ canonry wordpress connect <project> --url <url> --user <user> # connect (prompts for app password)
227
+ canonry wordpress disconnect <project> # disconnect
228
+ canonry wordpress status <project> # connection status
229
+ canonry wordpress pages <project> [--live|--staging] # list pages
230
+ canonry wordpress page <project> <slug> # show page detail
231
+ canonry wordpress create-page <project> --title <t> --slug <s> --content <c> # create page
232
+ canonry wordpress update-page <project> <slug> --content <c> # update page
233
+ canonry wordpress set-meta <project> <slug> --title <t> # set SEO meta (single page)
234
+ canonry wordpress set-meta <project> --from <file> # bulk set SEO meta from JSON
235
+ canonry wordpress schema <project> <slug> # read page JSON-LD
236
+ canonry wordpress schema deploy <project> --profile <file> # deploy schema from profile
237
+ canonry wordpress schema status <project> # schema status per page
238
+ canonry wordpress set-schema <project> <slug> # manual schema handoff
239
+ canonry wordpress audit <project> # audit pages for SEO issues
240
+ canonry wordpress diff <project> <slug> # compare live vs staging
241
+ canonry wordpress staging status <project> # staging config status
242
+ canonry wordpress staging push <project> # manual staging push handoff
243
+ canonry wordpress llms-txt <project> # read /llms.txt
244
+ canonry wordpress set-llms-txt <project> # manual llms.txt handoff
245
+ canonry wordpress onboard <project> --url <url> --user <user> # full onboarding workflow
246
+ ```
247
+
248
+ **Onboard** runs: connect → audit → set-meta → schema deploy → Google submit → Bing submit. Use `--skip-schema` or `--skip-submit` to skip steps. `--profile <file>` provides business data and page-to-schema mapping for schema deployment.
249
+
250
+ ## Google Analytics 4
251
+
252
+ GA4 integration uses service account authentication (no OAuth). The service account must have Viewer access on the GA4 property.
253
+
254
+ ```bash
255
+ canonry ga connect <project> --property-id <id> --key-file ./sa-key.json # connect GA4
256
+ canonry ga disconnect <project> # disconnect
257
+ canonry ga status <project> # connection status
258
+ canonry ga sync <project> [--days 30] [--only traffic|ai|social] # pull GA4 data (selective or full)
259
+ canonry ga traffic <project> # landing pages + AI/social referral sources
260
+ canonry ga coverage <project> # indexed pages with traffic overlay
261
+ canonry ga ai-referral-history <project> # daily AI referral history by source
262
+ canonry ga social-referral-history <project> # daily social referral history by source
263
+ canonry ga social-referral-summary <project> [--trend] # one-line social summary + optional trend
264
+ canonry ga attribution <project> [--trend] # unified channel attribution overview + optional trends
265
+ ```
266
+
267
+ ## CDP / Browser Provider
268
+
269
+ The CDP (Chrome DevTools Protocol) provider enables browser-based queries against AI chat interfaces (e.g., ChatGPT). This gives more accurate results than API-based providers for some use cases.
270
+
271
+ ```bash
272
+ canonry cdp connect --host localhost --port 9222 # connect to Chrome CDP
273
+ canonry cdp status # show connection status
274
+ canonry cdp targets # list available targets (ChatGPT, etc.)
275
+ canonry cdp screenshot <query> --targets chatgpt # screenshot a query result
276
+ ```
277
+
278
+ **Requires:** Chrome running with `--remote-debugging-port=9222`
279
+
280
+ ## Telemetry
281
+
282
+ ```bash
283
+ canonry telemetry status # show telemetry status
284
+ canonry telemetry enable # enable anonymous telemetry
285
+ canonry telemetry disable # disable telemetry
286
+ ```
287
+
288
+ ## Config as Code
289
+
290
+ ```bash
291
+ canonry apply project.yaml # apply declarative config
292
+ canonry apply file1.yaml file2.yaml # multiple files
293
+ canonry export <project> --include-results > project.yaml
294
+ canonry sitemap inspect <project>
295
+ ```
296
+
297
+ ## Agent (OpenClaw Integration)
298
+
299
+ `canonry agent setup` is the single entry point for configuring the agent. It handles everything:
300
+ canonry initialization, OpenClaw installation, profile setup, LLM credential configuration,
301
+ and workspace seeding. If canonry is not yet configured, it runs the interactive init flow first
302
+ (prompting for monitoring provider keys and agent LLM credentials).
303
+
304
+ ```bash
305
+ # Full setup (interactive — prompts for provider keys + agent LLM)
306
+ canonry agent setup
307
+
308
+ # Non-interactive (flags or env vars)
309
+ canonry agent setup --gemini-key <key> --agent-key <key>
310
+ canonry agent setup --agent-provider openrouter --agent-key <key> --agent-model openrouter/anthropic/claude-sonnet-4-6
311
+ GEMINI_API_KEY=<key> canonry agent setup --agent-key <key> --format json
312
+
313
+ # Lifecycle
314
+ canonry agent start # start OpenClaw gateway as background process
315
+ canonry agent stop # stop the gateway process
316
+ canonry agent status # check if gateway is running
317
+ canonry agent status --format json # JSON output
318
+ canonry agent reset # stop gateway and wipe workspace
319
+
320
+ # Setup flags
321
+ canonry agent setup --agent-provider <id> # LLM provider (default: anthropic)
322
+ canonry agent setup --agent-key <key> # API key for agent LLM
323
+ canonry agent setup --agent-model <model> # model id (e.g. anthropic/claude-sonnet-4-6)
324
+ canonry agent setup --gateway-port 3579 # gateway WebSocket port
325
+ canonry agent setup --gemini-key <key> # monitoring provider keys (passed to init)
326
+ canonry agent setup --openai-key <key>
327
+ canonry agent setup --claude-key <key>
328
+ canonry agent setup --perplexity-key <key>
329
+ ```
330
+
331
+ **Setup flow:** init canonry (if needed) → install OpenClaw (if needed) → configure profile → configure gateway → set agent LLM credentials → seed workspace with skills.
332
+
333
+ **Agent LLM credentials** are stored in `~/.openclaw-aero/.env` (e.g. `ANTHROPIC_API_KEY=...`) and loaded into the gateway process at start time. The model is set via `openclaw models set`.
334
+
335
+ **Re-running is safe:** setup is idempotent — it skips steps that are already configured.
336
+
337
+ ## Output Formats
338
+
339
+ Most commands support `--format json` for machine-readable output.
@@ -0,0 +1,155 @@
1
+ # Indexing Workflows for AEO
2
+
3
+ Getting pages indexed fast is high-leverage AEO work. Unindexed pages are invisible to AI citation regardless of content quality.
4
+
5
+ ## Priority Order
6
+
7
+ 1. **Google Indexing API** — fastest path to ChatGPT/Perplexity visibility (they lean on Google)
8
+ 2. **Bing WMT + IndexNow** — fastest path to Copilot/Bing AI visibility
9
+ 3. **Sitemap submission** — baseline for both; do once on setup
10
+
11
+ ---
12
+
13
+ ## Google Search Console
14
+
15
+ ### Check coverage
16
+ ```bash
17
+ canonry google coverage <project>
18
+ ```
19
+
20
+ Statuses to act on:
21
+ - `URL is unknown to Google` → highest priority, submit immediately
22
+ - `Discovered - currently not indexed` → Google found it but hasn't crawled — submit to accelerate
23
+ - `indexed` → no action needed
24
+
25
+ ### Sync GSC data
26
+ ```bash
27
+ canonry google sync <project> # incremental sync
28
+ canonry google sync <project> --full --wait # full re-sync
29
+ ```
30
+
31
+ ### Check search performance
32
+ ```bash
33
+ canonry google performance <project> # default 28 days
34
+ canonry google performance <project> --days 90 --keyword "term"
35
+ ```
36
+
37
+ ### Discover and inspect sitemaps
38
+ ```bash
39
+ canonry google discover-sitemaps <project> --wait # auto-discover sitemaps and queue inspection
40
+ canonry google list-sitemaps <project> # list submitted sitemaps
41
+ canonry google inspect-sitemap <project> --wait # bulk inspect all sitemap URLs
42
+ ```
43
+
44
+ ### Inspect individual URLs
45
+ ```bash
46
+ canonry google inspect <project> <url> # inspect specific URL
47
+ canonry google inspections <project> # inspection history
48
+ canonry google inspections <project> --url <url> # filter by URL
49
+ canonry google deindexed <project> # pages that lost indexing
50
+ ```
51
+
52
+ ### Submit URLs to Google Indexing API
53
+ ```bash
54
+ # Single URL
55
+ canonry google request-indexing <project> <url>
56
+
57
+ # All unindexed at once
58
+ canonry google request-indexing <project> --all-unindexed
59
+ ```
60
+
61
+ **Requirements:**
62
+ - "Web Search Indexing API" enabled in the GCP project
63
+ - OAuth connection set up in canonry (`canonry settings` shows Google connection)
64
+ - Officially intended for JobPosting/BroadcastEvent schema; in practice Google processes all URLs
65
+
66
+ **After submitting:** Check coverage again after 48h. Once indexed, run a sweep — pages must be indexed before citation is possible.
67
+
68
+ ---
69
+
70
+ ## Bing Webmaster Tools
71
+
72
+ ### One-time setup
73
+ ```bash
74
+ canonry bing connect <project> --api-key <key>
75
+ canonry bing set-site <project> https://example.com/
76
+ ```
77
+
78
+ Get API key from: https://www.bing.com/webmasters/ → Settings → API Access
79
+
80
+ ### Check connection and coverage
81
+ ```bash
82
+ canonry bing status <project>
83
+ canonry bing coverage <project>
84
+ canonry bing performance <project>
85
+ ```
86
+
87
+ ### Inspect URLs
88
+ ```bash
89
+ canonry bing inspect <project> <url>
90
+ canonry bing inspections <project>
91
+ ```
92
+
93
+ ### Submit URLs for indexing
94
+ ```bash
95
+ canonry bing request-indexing <project> <url>
96
+ canonry bing request-indexing <project> --all-unindexed
97
+ ```
98
+
99
+ ### Submit sitemap (manual, one-time)
100
+ Bing WMT → Sitemaps → submit `https://example.com/sitemap.xml`
101
+
102
+ ### IndexNow (instant crawl signal)
103
+ IndexNow is a direct ping to Bing: "these URLs changed, crawl them now." Without it, Bing discovers pages on its own schedule (days to weeks). With it, typically hours.
104
+
105
+ **Host the key file at the root:**
106
+ ```
107
+ https://example.com/<key>.txt
108
+ ```
109
+ File content: just the key string, nothing else.
110
+
111
+ **Submit URLs:**
112
+ ```bash
113
+ curl -X POST "https://www.bing.com/indexnow" \
114
+ -H "Content-Type: application/json; charset=utf-8" \
115
+ -d '{
116
+ "host": "example.com",
117
+ "key": "<key>",
118
+ "keyLocation": "https://example.com/<key>.txt",
119
+ "urlList": [
120
+ "https://example.com/",
121
+ "https://example.com/page-1"
122
+ ]
123
+ }'
124
+ ```
125
+
126
+ Expected response: `202 Accepted`
127
+
128
+ **Note:** IndexNow only covers Bing (and Yandex). It does NOT affect ChatGPT, Claude, or Gemini.
129
+
130
+ ---
131
+
132
+ ## When to Use What
133
+
134
+ | Goal | Tool |
135
+ |---|---|
136
+ | Get pages into ChatGPT / Perplexity / Claude | Google Indexing API |
137
+ | Get pages into Copilot / Bing AI | IndexNow + Bing WMT |
138
+ | Audit what Google currently knows | `canonry google coverage <project>` |
139
+ | Audit what Bing currently knows | `canonry bing coverage <project>` |
140
+ | Fast crawl of new/updated pages on Bing | IndexNow batch submit |
141
+ | Ongoing Google crawl health | `canonry google sync` + `canonry google performance` |
142
+ | Ongoing Bing crawl health | Bing WMT sitemap + `canonry bing performance` |
143
+ | Find deindexed pages | `canonry google deindexed <project>` |
144
+
145
+ ---
146
+
147
+ ## General Workflow for New Client Pages
148
+
149
+ 1. `canonry google coverage <project>` — identify unindexed pages
150
+ 2. `canonry google request-indexing <project> --all-unindexed` — push to Google
151
+ 3. `canonry bing request-indexing <project> --all-unindexed` — push to Bing
152
+ 4. Submit sitemap to Bing WMT (manual, one-time per site)
153
+ 5. Send IndexNow batch for key URLs
154
+ 6. Re-check coverage after 48h
155
+ 7. Run a sweep after pages confirmed indexed
@@ -0,0 +1,57 @@
1
+ # WordPress Integration
2
+
3
+ Canonry integrates with WordPress through the core REST API plus Application Passwords.
4
+
5
+ ## What Canonry Automates
6
+
7
+ - Read and write page content, titles, slugs, and status
8
+ - Audit pages for `noindex`, missing SEO title, missing meta description, missing schema, and thin content
9
+ - Compare live vs staging for a page with `canonry wordpress diff`
10
+ - Update SEO meta when the site exposes writable REST meta fields
11
+
12
+ ## What Stays Manual
13
+
14
+ Canonry generates payloads and instructions for these workflows, but it does not apply them remotely:
15
+
16
+ - `canonry wordpress set-schema`
17
+ - `canonry wordpress set-llms-txt`
18
+ - `canonry wordpress staging push`
19
+
20
+ Expect those commands to return:
21
+
22
+ - `manualRequired: true`
23
+ - generated content
24
+ - target/admin URL when available
25
+ - next-step instructions
26
+
27
+ ## Environment Model
28
+
29
+ Each project-scoped WordPress connection stores:
30
+
31
+ - live `url`
32
+ - optional `stagingUrl`
33
+ - `defaultEnv`
34
+ - `username`
35
+ - `appPassword`
36
+
37
+ Env-sensitive commands accept `--live` or `--staging`. If neither is provided, canonry uses `defaultEnv`.
38
+
39
+ ## Typical Workflow
40
+
41
+ ```bash
42
+ canonry wordpress connect mysite --url https://example.com --user admin --staging-url https://staging.example.com --default-env staging
43
+ canonry wordpress pages mysite --staging
44
+ canonry wordpress page mysite pricing --staging
45
+ canonry wordpress set-meta mysite pricing --title "SEO title" --description "Meta description" --staging
46
+ canonry wordpress audit mysite --staging
47
+ canonry wordpress diff mysite pricing
48
+ canonry wordpress staging push mysite
49
+ ```
50
+
51
+ ## Important Constraints
52
+
53
+ - WordPress auth is stored locally in `~/.canonry/config.yaml`
54
+ - Canonry does not use wp-admin automation or undocumented plugin APIs
55
+ - If SEO meta is not writable through REST, canonry returns an actionable error instead of guessing
56
+ - Duplicate slug matches are returned as explicit ambiguity errors with candidate page IDs/titles
57
+ - Authentication is verified on connect by calling `/wp/v2/users/me` — if that fails, canonry returns an actionable error message
@@ -6880,9 +6880,9 @@ async function googleRoutes(app, opts) {
6880
6880
  const project = resolveProject(app.db, request.params.name);
6881
6881
  let redirectUri;
6882
6882
  if (publicUrl) {
6883
- redirectUri = publicUrl.replace(/\/$/, "") + (opts.routePrefix ?? "/api/v1") + "/google/callback";
6883
+ redirectUri = publicUrl.replace(/\/$/, "") + "/api/v1/google/callback";
6884
6884
  } else if (opts.publicUrl) {
6885
- redirectUri = opts.publicUrl.replace(/\/$/, "") + (opts.routePrefix ?? "/api/v1") + "/google/callback";
6885
+ redirectUri = opts.publicUrl.replace(/\/$/, "") + "/api/v1/google/callback";
6886
6886
  } else {
6887
6887
  const proto = request.headers["x-forwarded-proto"] ?? "http";
6888
6888
  const host = request.headers.host ?? "localhost:4100";
@@ -14395,7 +14395,7 @@ var RunCoordinator = class {
14395
14395
  }
14396
14396
  async onRunCompleted(runId, projectId) {
14397
14397
  try {
14398
- this.intelligenceService.analyzeAndPersist(runId, projectId);
14398
+ await this.intelligenceService.analyzeAndPersist(runId, projectId);
14399
14399
  } catch (err) {
14400
14400
  log6.error("intelligence.failed", { runId, error: err instanceof Error ? err.message : String(err) });
14401
14401
  }